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

68

我在这个有用的问答中看到,可以使用reload(whatever_module)或者在Python 3中使用imp.reload(whatever_module)

我的问题是,如果我使用from whatever_module import *来导入模块呢?那么当我使用reload()时就没有whatever_module可供参考了。你们会因为我把整个模块引入全局命名空间而责备我吗? :)


20
关于你最后一个问题:是的。 - JoshAdel
10
(1) 鉴于这个问题是在愚人节问的(即使是两年前),我本来期望回答中会有更多幽默感。 (2) Python教程中提到:“然而(从模块中导入所有内容)在交互式会话中可以节省打字,但在我看来,这正是需要重新加载的情况(你刚刚修复了一个正在交互式测试中的函数错误,并希望不离开解释器来保留其他测试数据)。” (3) Catskul确实提供了与所提问完全相符的正确答案,请接受并点赞! - Marc van Leeuwen
Catskul的回答很好,但并不是“唯一正确”的:它不必要地创建了一个通常不在原始代码中的新符号X(请参见Ohad Cohen或我的答案以避免此副作用)。 - Eric O. Lebigot
8个回答

72

我同意“通常不要这样做”的共识,但是...

正确的答案是:

from importlib import reload
import X
reload(X)
from X import Y  # or * for that matter

2
通常情况下,这会将符号 X 添加到命名空间中,因此通过执行 reload(sys.modules["X"]) 而不是 import X 来避免在命名空间中使用 X。当然,这可能需要将 sys 添加到命名空间中,但它是一个常见的模块,不应该掩盖任何东西(而 X 可能会被添加的 import X 掩盖)。 - Eric O. Lebigot
2
如果你使用别名导入一个模块,那么在 reload 中就要使用这个别名。例如,对于 import XX as X,应该使用 reload(X) - Duccio A
当我从包的模块中导入对象(from package.module import object)时,这似乎不起作用。 - nocibambi
对于Python 3,特别是3.4+版本,您需要添加from importlib import reload。不幸的是,编辑此答案会出现“建议的编辑队列已满”的错误。 - Pierre H.

8

永远不要使用 import *;它会破坏可读性。

此外,请注意重新加载模块几乎从来没有用处。您无法预测在重新加载模块后您的程序将以什么状态结束,因此这是一种获得难以理解、无法重现的错误的好方法。


26
虽然在交互模式下很有用,但我经常更新我的模块,��后不得不退出并重新进入Python。 - murftown
6
如果你使用python -i foo.py,你可以让Python在给你提示符之前运行所有的设置代码。(而不是使用from somepackage.foo import *,为什么不使用from somepackage import foo as f,然后引用f.yourObjects等呢?) - Allen
啊,但是在我的Python 3中,我仍然不能使用“from somepackage import * as whatever”(至少目前如此)……我知道你们都不希望我能够这样做! ;) - murftown
我在这个问题上有一个重要的疑问。(五年晚了。) 如果我使用 import module as mod 来避免 from module import *, 那么我怎么用 mod 重新加载 module呢? - Jareth Holt
1
@JarethHolt,你可能现在已经明白了,但只需执行 reload(mod) - Junier
显示剩余2条评论

7
更清晰的答案是将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

1
sys.module 应该是 sys.modules。我尝试进行编辑,但只有三个字符... - bendl
1
我试图回复“已修复,谢谢!”但它只有14个字符,无法通过。 :) - Eric O. Lebigot

4

A

from module import *

module中获取所有“导出”的对象,并将它们绑定到模块级别(或者是你的作用域级别)的名称上。你可以通过以下方式重新加载模块:
reload(sys.modules['module'])

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


3

我找到了另一种处理像这样导入时重新加载模块的方法:

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'

如果您想在运行整个脚本时重新加载模块,可以使用异常处理程序:

try:
    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

不错!我喜欢那个解决方案。谢谢分享! - murftown

1

当使用from whatever_module import whatever导入时,whatever被视为导入模块的一部分,因此要重新加载它-您应该重新加载您的模块。但是,仅重新加载您的模块,您仍将获得旧的whatever-来自已导入的whatever_module,因此您需要重新加载(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

0
import re

for mod in sys.modules.values():
    if re.search('name', str(mod)):
        reload(mod)

-2

对于 Python 3.7:

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

可以从您自己的函数调用 Reload 函数

def yourFunc():
   reload(YourModule)

这条评论并没有回答原问题。 - johnnyheineken

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接