关于python:在IPython中重新加载子模块

Reloading submodules in IPython

目前我正在开发一个包含子模块并使用numpy / scipy的python项目。 Ipython用作交互式控制台。 不幸的是,我对我现在使用的工作流程不是很满意,我将不胜感激。

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

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


IPython带有一些自动重装魔法:

1
2
%load_ext autoreload
%autoreload 2

它会在执行新行之前每次重新加载所有已更改的模块。它的工作方式与dreload略有不同。一些警告适用,键入%autoreload?以查看可能出错的地方。

如果要始终启用此设置,请修改IPython配置文件~/.ipython/profile_default/ipython_config.py [1]并附加:

1
2
c.InteractiveShellApp.extensions = ['autoreload']    
c.InteractiveShellApp.exec_lines = ['%autoreload 2']

通过以下评论获得@Kos。

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


在IPython 0.12(可能更早)中,您可以使用:

1
2
%load_ext autoreload
%autoreload 2

这与pv。的答案基本相同,只是扩展名已重命名,现在使用%load_ext加载。


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


出于某种原因,当您将代码从一个笔记本导入另一个笔记本时,%autoreloaddreload似乎都不适用于这种情况。只有普通的Python reload有效:

1
reload(module)

基于[1]。


http://shawnleezx.github.io/blog/2015/08/03/some-notes-on-ipython-startup-script/

为了避免一次又一次地输入这些魔术函数,可以将它们放入ipython启动脚本(在.ipython / profile_default / startup下使用.py后缀命名。该文件夹下的所有python脚本将根据词法顺序加载),看起来如下:

1
2
3
4
5
6
from IPython import get_ipython
ipython = get_ipython()

ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")

这个怎么样:

1
2
3
4
5
6
7
8
9
10
11
12
13
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中(我认为),以便每次启动解释器时都会加载它。


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

1
2
import importlib
importlib.reload(my_module)

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

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


另外一个选项:

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

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


我重新加载的标准做法是在首次打开IPython后合并两种方法:

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

在执行此操作之前加载模块将导致它们无法重新加载,即使使用手动reload(module_name)也是如此。我仍然非常罕见地遇到了无法重新加载的类方法的莫名其妙的问题,我还没有考虑过。


在关于Anaconda的Jupyter笔记本上,这样做:

1
2
%load_ext autoreload
%autoreload 2

产生了消息:

The autoreload extension is already loaded. To reload it, use:
%reload_ext autoreload

看起来最好这样做:

1
2
%reload_ext autoreload
%autoreload 2

版本信息:

The version of the notebook server is 5.0.0 and is running on:
Python 3.6.2 |Anaconda, Inc.| (default, Sep 20 2017, 13:35:58) [MSC v.1900 32 bit (Intel)]