如何让 IPython 重新加载传递给 `ipython -i ...` 的文件
How do I make IPython reload a file passed to `ipython -i ...`
我有一个文件 /tmp/throwaway_code.py,里面有类似
的东西
def hello():
print("world")
并尝试使用 IPython:
$ ipython3 -i /tmp/throwaway_code.py
In [1]: hello()
world
现在我更改了文件中的某些内容并想重新加载。如何在不重新启动 IPython 或模块化代码的情况下做到这一点?
我失败的尝试:
In [2]: %load_ext autoreload
In [3]: %autoreload 2
# change source file
In [4]: hello()
world
# Expected: world2.
或者,我如何轻松离开并重新进入 IPython 会话(目前需要 6 次击键:Ctrl、D、y、Return、向上、Return)?
autoreload
在这里不起作用,该模块未使用 -i
选项放置在 sys.modules
中:
from sys import modules
modules['throwaway_code'] # KeyError
所以 reload
找不到您要重新加载的模块。
一种解决方法是显式 import
将其放置在 sys.modules
中的模块,然后 autoreload
每次都会抓取更改。因此,您应该退出 IPython 并以适当的 PYTHONPATH
启动它,以便您的代码可以作为模块导入。您的会话应如下所示:
In [4]: ^D
Do you really want to exit ([y]/n)? y
$ PYTHONPATH=/tmp ipython3
In [1]: from throwaway_code import *
In [2]: %load_ext autoreload
In [3]: %autoreload 2
In [4]: hello()
world
In [5]: hello()
world2
在IPython3中,使用reload(mymodule),你可以重新加载同一个包中的所有模块。只需将此代码粘贴到 IPython3 启动文件夹中的 reload.py(在 Ubuntu 上是“~/.ipython/profile_default/startup/”)
import importlib
from types import ModuleType
import compileall
from filecmp import dircmp
from os.path import dirname
from glob import glob
from os.path import join
blacklist=[]
def reload(module,blacklist_appendix=[]):
"""Recursively reload modules."""
file_paths=glob(join(dirname(module.__file__),"*.py"))
print(file_paths)
_reload(module,blacklist+blacklist_appendix,file_paths)
def _reload(module, blacklist=[],file_paths=[],reloadeds=[]):
if module.__name__ in blacklist:
print("not reloaded: "+module.__name__)
return False
if (module.__dict__.get("__file__")==None
or not (module.__file__ in file_paths)
or module.__file__ in reloadeds):
return False
reloadeds.append(module.__file__ )
for attribute_name in dir(module):
attribute = getattr(module, attribute_name)
if type(attribute) is ModuleType:
_reload(attribute,file_paths=file_paths,reloadeds=reloadeds)
compileall.compile_file(module.__file__,force=True)
print("reload start: "+module.__name__)
importlib.reload(module)
print("reloaded: "+module.__name__)
我有一个文件 /tmp/throwaway_code.py,里面有类似
的东西def hello():
print("world")
并尝试使用 IPython:
$ ipython3 -i /tmp/throwaway_code.py
In [1]: hello()
world
现在我更改了文件中的某些内容并想重新加载。如何在不重新启动 IPython 或模块化代码的情况下做到这一点?
我失败的尝试:
In [2]: %load_ext autoreload
In [3]: %autoreload 2
# change source file
In [4]: hello()
world
# Expected: world2.
或者,我如何轻松离开并重新进入 IPython 会话(目前需要 6 次击键:Ctrl、D、y、Return、向上、Return)?
autoreload
在这里不起作用,该模块未使用 -i
选项放置在 sys.modules
中:
from sys import modules
modules['throwaway_code'] # KeyError
所以 reload
找不到您要重新加载的模块。
一种解决方法是显式 import
将其放置在 sys.modules
中的模块,然后 autoreload
每次都会抓取更改。因此,您应该退出 IPython 并以适当的 PYTHONPATH
启动它,以便您的代码可以作为模块导入。您的会话应如下所示:
In [4]: ^D
Do you really want to exit ([y]/n)? y
$ PYTHONPATH=/tmp ipython3
In [1]: from throwaway_code import *
In [2]: %load_ext autoreload
In [3]: %autoreload 2
In [4]: hello()
world
In [5]: hello()
world2
在IPython3中,使用reload(mymodule),你可以重新加载同一个包中的所有模块。只需将此代码粘贴到 IPython3 启动文件夹中的 reload.py(在 Ubuntu 上是“~/.ipython/profile_default/startup/”)
import importlib
from types import ModuleType
import compileall
from filecmp import dircmp
from os.path import dirname
from glob import glob
from os.path import join
blacklist=[]
def reload(module,blacklist_appendix=[]):
"""Recursively reload modules."""
file_paths=glob(join(dirname(module.__file__),"*.py"))
print(file_paths)
_reload(module,blacklist+blacklist_appendix,file_paths)
def _reload(module, blacklist=[],file_paths=[],reloadeds=[]):
if module.__name__ in blacklist:
print("not reloaded: "+module.__name__)
return False
if (module.__dict__.get("__file__")==None
or not (module.__file__ in file_paths)
or module.__file__ in reloadeds):
return False
reloadeds.append(module.__file__ )
for attribute_name in dir(module):
attribute = getattr(module, attribute_name)
if type(attribute) is ModuleType:
_reload(attribute,file_paths=file_paths,reloadeds=reloadeds)
compileall.compile_file(module.__file__,force=True)
print("reload start: "+module.__name__)
importlib.reload(module)
print("reloaded: "+module.__name__)