目前我正在开发一个包含子模块并使用 numpy/scipy 的 python 项目。 Ipython 用作交互式控制台。不幸的是,我对我现在使用的工作流程不是很满意,我会很感激一些建议。
在 IPython 中,框架由一个简单的 import
命令加载。但是,经常需要更改框架的子模块之一中的代码。此时已经加载了一个模型,我使用 IPython 与之交互。
现在,框架包含许多相互依赖的模块,即当框架最初加载时,主模块正在导入和配置子模块。仅当使用 reload(main_mod.sub_mod)
重新加载模块时才会执行对代码的更改。这很麻烦,因为我需要使用完整路径单独重新加载所有更改的模块。如果 reload(main_module)
也重新加载所有子模块,但不重新加载 numpy/scipy..
However, it is often necessary to change code in one of the submodules of the framework.
那么为什么是 necessary to change code
?谢谢
IPython 带有一些 automatic reloading 魔法:
%load_ext autoreload
%autoreload 2
每次执行新行之前,它都会重新加载所有更改的模块。它的工作方式与 dreload
略有不同。有一些注意事项,请输入 %autoreload?
以查看可能出现的问题。
如果您想始终启用此设置,请修改您的 IPython 配置文件 ~/.ipython/profile_default/ipython_config.py
[1] 并附加:
c.InteractiveShellApp.extensions = ['autoreload']
c.InteractiveShellApp.exec_lines = ['%autoreload 2']
通过下面的评论感谢@Kos。
[1] 如果您没有文件 ~/.ipython/profile_default/ipython_config.py
,则需要先调用 ipython profile create
。或者该文件可能位于 $IPYTHONDIR
。
名为 importlib
的模块允许访问导入内部。特别是,它提供了函数 importlib.reload()
:
import importlib
importlib.reload(my_module)
与 %autoreload
不同,importlib.reload()
还重置模块中设置的全局变量。在大多数情况下,这就是您想要的。
importlib
仅从 Python 3.1 开始可用。对于旧版本,您必须使用模块 imp
。
我建议阅读 importlib.reload()
的文档以获取此函数的所有警告列表(递归重新加载、保留旧对象定义的情况等)。
在 IPython 0.12(可能更早)中,你可以使用这个:
%load_ext autoreload
%autoreload 2
这与 pv. 的答案基本相同,只是扩展已被重命名并且现在使用 %load_ext
加载。
出于某种原因,%autoreload
和 dreload
似乎都不适用于您 import code from one notebook to another 的情况。只有普通的 Python reload
有效:
reload(module)
基于 [1]。
%autoreload
技术不同,此方法在添加实例方法时有效。有一个 open bug report to add support to %autoreload
for this.。
IPython 提供 dreload()
以递归方式重新加载所有子模块。就个人而言,我更喜欢使用 %run()
魔法命令(尽管它不会执行深度重新加载,正如 John Salvatier 在评论中指出的那样)。
dreload
在最近的 IPython(例如 IPython 6.0)中已被 deepreload 取代。
http://shawnleezx.github.io/blog/2015/08/03/some-notes-on-ipython-startup-script/
为了避免一次又一次地输入这些神奇的函数,可以将它们放在 ipython 启动脚本中(在 .ipython/profile_default/startup 下以 .py 后缀命名。该文件夹下的所有 python 脚本将根据词法顺序加载),其中如下所示:
from IPython import get_ipython
ipython = get_ipython()
ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")
%run script.py
运行脚本,这似乎也有效
这个怎么样:
import inspect
# needs to be primed with an empty set for loaded
def recursively_reload_all_submodules(module, loaded=None):
for name in dir(module):
member = getattr(module, name)
if inspect.ismodule(member) and member not in loaded:
recursively_reload_all_submodules(member, loaded)
loaded.add(module)
reload(module)
import mymodule
recursively_reload_all_submodules(mymodule, set())
这应该有效地重新加载您提供的整个模块和子模块树。您也可以将此函数放在您的 .ipythonrc 中(我认为),以便每次启动解释器时都会加载它。
from ... import ...
或 import ... as
导入的模块或模块成员。至少这在终端上以交互方式工作时经常给我带来一些麻烦。我继续使用 IPython 中的存储宏来执行必要的导入和设置以开始在预定义的状态下工作。
from ... import ...
和 import ... as
。它唯一没有涵盖的是包中的模块,这些模块不是从它的 __init__.py
文件中加载的。对于包,您可能可以检查模块的 __path__
属性是否为目录。如果是,遍历它并递归地导入你能找到的所有模块。我没有写这部分,因为作者没有要求提供包的解决方案。
pkgutil
获取包中的所有子模块,即使该包没有将子模块导入顶级模块。 stackoverflow.com/a/1707786/1243926
sys.modules:
中的模块
我重新加载的标准做法是在第一次打开 IPython
后结合这两种方法:
from IPython.lib.deepreload import reload
%load_ext autoreload
%autoreload 2
在执行此操作之前加载模块将导致它们不会被重新加载,即使使用手动 reload(module_name)
也是如此。我仍然很少遇到无法重新加载的类方法的莫名问题,我还没有研究过。
在您的模块导入之前包括这些行,其中第一个测试是否已经加载了 autoreload 扩展:
if 'autoreload' not in get_ipython().extension_manager.loaded:
%load_ext autoreload
%autoreload 2
import sys
.
.
.
另外的选择:
$ cat << EOF > ~/.ipython/profile_default/startup/50-autoreload.ipy
%load_ext autoreload
%autoreload 2
EOF
在 Ubuntu 14.04 上的 ipython 和 ipython3 v5.1.0 上验证。
我讨厌向长线程添加另一个答案,但我找到了一个解决方案,可以在 %run()
上递归重新加载其他人可能会觉得有用的子模块(无论如何我都有)
del
您希望在 iPython 中从 sys.modules
运行时重新加载的子模块:
In[1]: from sys import modules
In[2]: del modules["mymodule.mysubmodule"] # tab completion can be used like mymodule.<tab>!
现在您的脚本将递归地重新加载此子模块:
In[3]: %run myscript.py
请注意,如果您手动保存更改的文件(例如使用 ctrl+s 或 cmd+s),上述 autoreload
仅适用于 IntelliJ。它似乎不适用于自动保存。
在 Anaconda 上的 Jupyter Notebooks 上,执行以下操作:
%load_ext autoreload
%autoreload 2
产生了消息:
自动重新加载扩展已加载。要重新加载它,请使用:%reload_ext autoreload
看起来最好这样做:
%reload_ext autoreload
%autoreload 2
版本信息:
笔记本服务器的版本是 5.0.0,运行于:Python 3.6.2 |Anaconda, Inc.| (默认,2017 年 9 月 20 日,13:35:58)[MSC v.1900 32 位(英特尔)]
任何子对象都不会因此而重新加载,我相信您必须为此使用 IPython 的 deepreload。
不定期副业成功案例分享
~/.ipython/profile_default/ipython_config.py
中有c.InteractiveShellApp.extensions = ['autoreload']
和c.InteractiveShellApp.exec_lines = ['%autoreload 2']
。