在IPython中重新加载子模块

目前,我正在研究一个包含子模块的python项目,并使用numpy/scipy。使用Ipython作为交互控制台。不幸的是,我对我现在使用的工作流程不是很满意,我很感激一些建议。

在IPython中,框架是通过一个简单的import命令加载的。但是,经常需要更改框架的一个子模块中的代码。此时,已经加载了一个模型,我使用IPython与它交互。

现在,框架包含许多相互依赖的模块,也就是说,当框架最初加载时,主模块正在导入和配置子模块。只有使用reload(main_mod.sub_mod)重新加载模块时,才会执行对代码的更改。这很麻烦,因为我需要使用完整的路径单独重新加载所有更改的模块。如果reload(main_module)也会重载所有子模块,但不重载numpy/scipy..

247284 次浏览

这个怎么样:

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(我认为)中,这样每次你启动解释器时都会加载它。

IPython提供了dreload()来递归重载所有子模块。就我个人而言,我更喜欢使用%run()魔法命令(尽管它不执行深度重载,正如John Salvatier在评论中指出的那样)。

IPython带有一些自动重新加载魔法:

%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。

< p > [1] 如果你没有文件~/.ipython/profile_default/ipython_config.py,你需要先调用ipython profile create。或者文件可能位于$IPYTHONDIR.

在IPython 0.12(可能更早)中,你可以使用这个:

%load_ext autoreload
%autoreload 2

这本质上与pv。的答案相同,除了扩展已经被重命名并且现在使用%load_ext加载。

由于某种原因,%autoreloaddreload似乎都不适用于你将代码从一个笔记本导入到另一个笔记本的情况。只有普通的Python reload可以工作:

reload(module)

基于[1]

另一个选择:

$ cat << EOF > ~/.ipython/profile_default/startup/50-autoreload.ipy
%load_ext autoreload
%autoreload 2
EOF

已在Ubuntu 14.04的ipython和ipython3 v5.1.0上验证。

我重新加载的标准做法是在IPython第一次打开之后结合这两个方法:

from IPython.lib.deepreload import reload
%load_ext autoreload
%autoreload 2

在此之前加载模块将导致它们不会被重新加载,即使使用手动reload(module_name)。我仍然很少遇到类方法不能重新加载的难以解释的问题,我还没有深入研究。

在阿纳康达的Jupyter笔记本上,这样做:

%load_ext autoreload
%autoreload 2

产生的消息:

自动加载扩展已经加载。要重新加载,请使用: %reload_ext autoreload < / p >

看起来更可取的做法是:

%reload_ext autoreload
%autoreload 2

版本信息:

笔记本服务器的版本是5.0.0并且正在运行: Python 3.6.2 |Anaconda, Inc.|(默认,Sep 20 2017, 13:35:58) [MSC v.1900 32 bit (Intel)]

< a href = " http://shawnleezx.github。io /博客/ 2015/08/03 / some-notes-on-ipython-startup-script noreferrer“rel = > 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")

命名为importlib的模块允许访问导入内部。特别是,它提供了函数importlib.reload():

import importlib
importlib.reload(my_module)

%autoreload相反,importlib.reload()也重置模块中设置的全局变量。在大多数情况下,这就是你想要的。

importlib仅在Python 3.1之后可用。对于旧版本,你必须使用模块imp

我建议阅读importlib.reload()的文档,以获得该函数的所有警告列表(递归重载,保留旧对象定义的情况,等等…)。

任何子对象都不会被重载,我相信你必须使用IPython的deepreload。

请注意,上面提到的autoreload只适用于IntelliJ,如果你手动保存更改的文件(例如使用ctrl+s或cmd+s)。它好像不能自动保存。

我讨厌在一个长线程中添加另一个答案,但我发现了一个解决方案,可以在%run()上递归重新加载子模块,其他人可能会发现有用(反正我有)

在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

在你的模块导入之前,包括这些行,其中第一个测试是否已经加载了自动加载扩展:

if 'autoreload' not in get_ipython().extension_manager.loaded:
%load_ext autoreload
%autoreload 2


import sys
.
.
.