ChatGPT解决这个技术问题 Extra ChatGPT

在 IPython 中重新加载子模块

目前我正在开发一个包含子模块并使用 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?谢谢
@eat:该框架正在不断开发中,因此代码库会不断变化。

B
Brad Koch

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


我的 ~/.ipython/profile_default/ipython_config.py 中有 c.InteractiveShellApp.extensions = ['autoreload']c.InteractiveShellApp.exec_lines = ['%autoreload 2']
不过,这可能会影响性能,因此请谨慎使用。
仅当您在 Ipython shell 中按 Enter 时才会执行重新加载,并且通常不会引起注意。
这在调试包时工作得很好,所以 dreload 的目的是什么,似乎 dreload 太具有侵入性并且在加载一些像 matplotlib 这样的包时会打印错误。
如果您使用@Kos 方法,请确保已定义 c:c = get_config()
J
Jérôme Pouiller

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

import importlib
importlib.reload(my_module)

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

importlib 仅从 Python 3.1 开始可用。对于旧版本,您必须使用模块 imp

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


在过去的两年里,我多次搜索这个问题,每次你的答案都是我正在寻找的完美答案。谢谢你。
C
Community

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

%load_ext autoreload
%autoreload 2

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


对 Jupyter 实验室的我来说,这项工作足够短,可以放入所有需要它的笔记本中。
C
Community

出于某种原因,%autoreloaddreload 似乎都不适用于您 import code from one notebook to another 的情况。只有普通的 Python reload 有效:

reload(module)

基于 [1]


在 Python 3.4+ 中,您可以在 importlib 模块中找到 reload。请参阅this question
%autoreload 技术不同,此方法在添加实例方法时有效。有一个 open bug report to add support to %autoreload for this.
S
Sven Marnach

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


我认为(不幸的是) %run script.py 只会重新加载您正在调用的脚本,而不是它导入的包。如果您尝试调试正在构建的包,这可能会很痛苦。
注意。 dreload 在最近的 IPython(例如 IPython 6.0)中已被 deepreload 取代。
P
Pegasus

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")

如果您使用例如来自 IPython REPL 的 %run script.py 运行脚本,这似乎也有效
Y
Y.H Wong

这个怎么样:

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__ 属性是否为目录。如果是,遍历它并递归地导入你能找到的所有模块。我没有写这部分,因为作者没有要求提供包的解决方案。
确实这看起来不错。我考虑过这种可能性,同时我希望会有一些内置功能,即基于this。但是,我不清楚如何使用它。在我发布原始问题之前应该进行一些挖掘之后,我发现了这个 extension
您也可以使用 pkgutil 获取包中的所有子模块,即使该包没有将子模块导入顶级模块。 stackoverflow.com/a/1707786/1243926
您还必须这样做:对于 sys.modules: 中的模块
r
ryanjdillon

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

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

在执行此操作之前加载模块将导致它们不会被重新加载,即使使用手动 reload(module_name) 也是如此。我仍然很少遇到无法重新加载的类方法的莫名问题,我还没有研究过。


u
user3897315

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

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

import sys
    .
    .
    .

L
Leo

另外的选择:

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

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


r
rdmolony

我讨厌向长线程添加另一个答案,但我找到了一个解决方案,可以在 %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

H
Hubert Grzeskowiak

请注意,如果您手动保存更改的文件(例如使用 ctrl+s 或 cmd+s),上述 autoreload 仅适用于 IntelliJ。它似乎不适用于自动保存。


我确认 PyCharm 也是如此。
t
thanks_in_advance

在 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 位(英特尔)]


a
aoeu256

任何子对象都不会因此而重新加载,我相信您必须为此使用 IPython 的 deepreload。