如何重新加载使用 "from module import *"导入的python模块?

56 人关注

我看到在 this useful Q&A 即可以使用 reload(whatever_module) 或者在Python 3中使用 imp.reload(whatever_module)

我的问题是,如果我说 from whatever_module import * 是为了进口呢? 那么当我使用 reload() 时,我就没有 whatever_module 可以参考了。你们会不会因为我把整个模块扔到全局命名空间而大骂?)

3 个评论
关于你的最后一个问题。是的。
(1) 鉴于这个问题是在4月1日提出的(即使是两年前),我本以为答案会更幽默一点。(2) Python 教程中说:"然而 [从模块中导入 *] 是可以在交互式会话中节省打字的;在我看来,这就是 正是 需要重新加载的情况(你刚刚修复了一个你正在交互式测试的函数中的错误,并希望不离开解释器以保持你的其他测试数据)。(3) Catskul确实对提出的问题提供了唯一的正确答案;请接受并投上一票
Catskul的答案很好,但不是 "唯一正确 "的答案:它不必要地创建了一个新的符号 X ,而这个符号一般不在原代码中(关于如何避免这种副作用,见Ohad Cohen的答案或我的答案)。
python
python-import
python-module
murftown
murftown
发布于 2011-04-02
8 个回答
Catskul
Catskul
发布于 2018-12-28
已采纳
0 人赞同

我同意 "一般不要这样做" consensus, but...

正确答案是。

from importlib import reload
import X
reload(X)
from X import Y  # or * for that matter
    
这通常是 增加 符号 X 到命名空间中,所以尊重 X 不在命名空间中的原则,改成 reload(sys.modules["X"]) 是比较干净的。当然,这可能需要将 sys 添加到名字空间中,但它是如此常见的模块,这不应该有任何阴影(而 X 可能会被添加的 import X 所阴影)。
如果你导入一个带有别名的模块,请在 reload 中使用该别名。例如,对于 import XX as X 使用 reload(X)
当我从一个包的模块中导入一个对象时,这似乎不起作用( from package.module import object )。
对于Python 3,特别是3.4+,你需要添加 from importlib import reload 。不幸的是,编辑这个答案会产生错误 "建议的编辑队列已满"。
Allen
Allen
发布于 2018-12-28
0 人赞同

不要使用 import * ;它破坏了可读性。

另外,请注意,重载模块几乎没有用处。你无法预测你的程序在重载模块后最终会处于什么状态,所以这是一个获得不可理解的、无法产生的错误的好方法。

不过在交互式模式下是很有用的,我总是在更新我的模块,然后不得不退出来再回到python中。
这也是为什么我使用import * from ___的原因,只是为了交互式模式,这样我就不用打那么多字了。
如果你使用 python -i foo.py ,你可以让Python在给你提示之前运行所有的设置代码。(而不是 from somepackage.foo import * ,为什么不使用 from somepackage import foo as f ,然后参考 f.yourObjects ,等等?
啊,但我还是不能从某个包中导入*作为什么(至少在我的Python 3中)......我知道你们都不希望我能够这样做!;)
@JarethHolt,你现在可能已经明白了,但只要做 reload(mod) 就可以了。
Eric O Lebigot
Eric O Lebigot
发布于 2018-12-28
0 人赞同

一个更干净的答案是Catskul的好答案和Ohad Cohen使用 sys.modules 和直接重新定义的混合。

import sys
Y = reload(sys.modules["X"]).Y  # reload() returns the new module

事实上,做import X会创建一个新的符号(X),可能会在后面的代码中被重新定义,这是没有必要的(而sys是一个普通的模块,所以不应该发生这种情况)。

这里有趣的一点是,from X import Y并没有将X添加到命名空间。而是将模块X添加到已知模块列表(sys.modules)中,这使得该模块可以被重新加载(以及访问其新内容)。

更为普遍的是,如果需要更新多个导入的符号,那么像这样导入它们会更加方便。

import sys
reload(sys.modules["X"])  # No X symbol created!
from X import Y, Z, T
    
sys.module 应该是 sys.modules 。我试图编辑,但它只有3个字符......
我试图回应 "固定的,谢谢!"但只有14个字符,没有被接受。 :)
tzot
tzot
发布于 2018-12-28
0 人赞同
from module import *

module中获取所有 "导出 "的对象,并将它们绑定到模块级(或任何你的范围级)的名称。你可以重新加载该模块为。

reload(sys.modules['module'])

但这对你没有任何好处:不管你的范围是什么级别的名称仍然指向旧的对象。

ksiu
ksiu
发布于 2018-12-28
0 人赞同

我找到了另一种方法来处理导入时重新加载模块的问题,比如。

from directory.module import my_func

能知道模块一般是如何被导入的,这很好。 模块在sys.modules的字典中被搜索到。如果它已经存在于sys.modules中--该模块将不会被再次导入。

因此,如果我们想重新加载我们的模块,我们可以从sys.modules中删除它,然后重新导入。

import sys
from directory.module import my_func
my_func('spam')
# output: 'spam'
# here I have edited my_func in module.py
my_func('spam') # same result as above
#output: 'spam'
del sys.modules[my_func.__module__]
from directory.module import my_func
my_func('spam') # new result
#output: 'spam spam spam spam spam'

如果你想在运行整个脚本时获得重载模块,你可以使用异常处理程序。

del sys.modules[my_func.__module__] except NameError as e: print("""Can't remove module that haven't been imported. Error: {}""".format(e)) from utils.module import my_func .......... # code of the script here
很好!我喜欢这个解决方案。谢谢你的分享!
Ohad Cohen
Ohad Cohen
发布于 2018-12-28
0 人赞同

当使用 from whatever_module import whatever 导入时, whatever 被算作导入模块的一部分,所以要重新加载它 - 你应该重新加载你的模块。但是,仅仅重新加载你的模块,你仍然会得到旧的 whatever 。- 所以你需要重新加载(whatever_module),然后再重新加载你的模块。

# reload(whatever_module), if you imported it
reload(sys.modules['whatever_module'])
reload(sys.modules[__name__])

如果你使用from whatever_module import whatever,你也可以考虑

whatever=reload(sys.modules['whatever_module']).whatever
whatever=reload(whatever_module).whatever
    
jennifer
jennifer
发布于 2018-12-28
0 人赞同
import re
for mod in sys.modules.values():
    if re.search('name', str(mod)):
        reload(mod)
    
Veniamin Magnet
Veniamin Magnet
发布于 2018-12-28
0 人赞同

for python 3.7 :

from importlib import reload #import function "reload"
import YourModule #import your any modules
reload(YourModule) #reload your module