【问题标题】:How to reload python module imported using `from module import *`如何重新加载使用`from module import *`导入的python模块
【发布时间】:2011-07-27 20:53:21
【问题描述】:

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

我的问题是,如果我说 from whatever_module import * 导入会怎样?那么当我使用reload() 时,我没有whatever_module 可以参考。你们会因为我把整个模块扔进全局命名空间而对我大喊大叫吗? :)

【问题讨论】:

  • 关于你的最后一个问题:是的。
  • (1) 鉴于这个问题是在 4 月 1 日提出的(即使是两年前),我本以为答案会更幽默一些。 (2) Python 教程说“但是 [importing * from a module] 可以在交互式会话中保存输入;在我看来,这正是需要重新加载的情况(您刚刚修复了您正在交互测试的函数中的错误,并且希望不要离开解释器来保留您的其他测试数据)。(3)Catskul 确实提供了对所提出问题的唯一正确答案;请接受并投票!
  • Catskul 的答案很好,但不是“唯一正确”的答案:它不必要地创建了一个通常不在原始代码中的新符号 X(有关如何避免,请参阅 Ohad Cohen 或我的答案这种副作用)。

标签: python python-import python-module


【解决方案1】:

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

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

【讨论】:

  • 不错!我喜欢那个解决方案。感谢分享!
【解决方案2】:

对于python 3.7:

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

可以从你自己的函数中调用重载函数

def yourFunc():
   reload(YourModule)

【讨论】:

  • 这条评论没有回答原问题
【解决方案3】:

更简洁的答案是 Catskul 的好答案和 Ohad Cohen 对 sys.module 的使用和直接重新定义的混合:

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

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

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

更一般地说,如果需要更新多个导入的符号,那么像这样导入它们会更方便:

import sys
reload(sys.module["X"])  # No X symbol created!
from X import Y, Z, T

【讨论】:

    【解决方案4】:

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

    正确答案是:

    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) 的模块中导入对象时,这似乎不起作用。
    【解决方案5】:
    import re
    
    for mod in sys.modules.values():
        if re.search('name', str(mod)):
            reload(mod)
    

    【讨论】:

      【解决方案6】:

      使用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
      

      【讨论】:

        【解决方案7】:

        一个

        from module import *
        

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

        reload(sys.modules['module'])
        

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

        【讨论】:

          【解决方案8】:

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

          另外,请注意重新加载模块几乎没有用处。你无法预测你的程序在重新加载一个模块后最终会处于什么状态,所以这是一个很好的方法来解决难以理解的、无法重现的错误。

          【讨论】:

          • 虽然它在交互模式下很有用,但我总是在更新我的模块,然后不得不退出并返回 python。
          • 这也是我使用 import * from ___ 的原因,只是为了交互模式,所以我不必输入太多
          • 如果你使用python -i foo.py,你可以让python在它给你提示之前运行你所有的设置代码。 (而不是from somepackage.foo import *,为什么不使用from somepackage import foo as f,然后参考f.yourObjects等?
          • 啊,但我仍然不能从 somepackage import * 做任何事情(至少在我的 python 3 中)......我知道你们都不希望我能够做到这一点! ;)
          • @JarethHolt,您现在可能已经想通了,但请执行reload(mod)
          猜你喜欢
          • 2014-04-21
          • 1970-01-01
          • 1970-01-01
          • 2012-11-07
          • 2014-04-19
          • 1970-01-01
          • 1970-01-01
          • 2012-10-22
          相关资源
          最近更新 更多