【问题标题】:Reimport a module in python while interactive在交互时重新导入python中的模块
【发布时间】:2010-11-18 06:28:15
【问题描述】:

我知道可以做到,但我不记得怎么做。

如何在 python 中重新导入模块? 场景如下:我以交互方式导入一个模块并对其进行修改,但随后我遇到了错误。我修复了 .py 文件中的错误,然后我想在不退出 python 的情况下重新导入修复的模块。我该怎么做?

【问题讨论】:

标签: python


【解决方案1】:

对于Python 3.4+

import importlib
importlib.reload(nameOfModule)

对于 Python :

reload(my.module)

来自Python docs

重新加载以前导入的模块。参数必须是模块对象,所以它必须之前已经成功导入。如果您已使用外部编辑器编辑了模块源文件并想在不离开 Python 解释器的情况下试用新版本,这将非常有用。

不要忘记使用此方法的注意事项:

  • 当一个模块被重新加载时,它的字典(包含模块的全局变量)被保留。重新定义名称会覆盖旧定义,因此这通常不是问题,但如果模块的新版本没有定义旧版本定义的名称,则不会删除旧定义。

  • 如果一个模块使用from ... import ...从另一个模块导入对象,则为另一个模块调用reload()不会重新定义从它导入的对象——解决这个问题的一种方法是重新执行from语句,另一种是改为使用 import 和限定名称 (module.*name*)。

  • 如果一个模块实例化了一个类的实例,重新加载定义该类的模块不会影响实例的方法定义——它们会继续使用旧的类定义。派生类也是如此。

【讨论】:

  • 如果我使用 from filename import * 加载我的模块。如何重新加载?
  • @PeterZhu 对于“from mod import fcn”的情况,模块对象没有添加到命名空间。所以你需要显式地导入模块,以便以后重新加载它。 import foo; from foo import bar; reload(foo)
  • 我尝试了重新加载以及自动重新加载魔法,我看到我的代码更改反映在错误消息的堆栈中,但错误本身似乎仍然是过时的代码(例如,行的错误与以前完全相同,我已将其更改为注释,并且注释显然不会导致错误)。我的模块作为 Jupyter 扩展加载,可能有人知道这是否需要不同的解决方法?谢谢!
  • 如果你导入你的函数如下“import mod as name”,那么你需要做如下:'import importlib importlib.reload(name)'
  • 此方法可能不会覆盖其他模块对重新加载模块的引用。请参阅stackoverflow.com/a/61617169/2642356 以获取解决方案。
【解决方案2】:

在 python 3 中,reload 不再是内置函数。

如果您使用的是 python 3.4+,则应使用 reload 库中的 reload 代替:

import importlib
importlib.reload(some_module)

如果您使用的是 python 3.2 或 3.3,您应该:

import imp  
imp.reload(module)  

相反。见http://docs.python.org/3.0/library/imp.html#imp.reload

如果您使用的是ipython,请务必考虑使用autoreload 扩展:

%load_ext autoreload
%autoreload 2

【讨论】:

  • @Andrew 谢谢!我使用了 %autoreload,太棒了,我已经创建的对象自动得到了类方法的正确实现,而无需重新创建它们
  • 我有点晚了,但我认为如果你需要重新加载的是模块内的函数或类,这不起作用:如果我的导入语句是from mymodule import myfunc,那么@987654336 @、importlib.reload(mymodule.myfunc)importlib.reload(mymodule) 都给出了 NameError。
  • @Puff 请参阅 my answer below 了解如何重新导入函数
【解决方案3】:

实际上,在 Python 3 中,模块 imp 被标记为已弃用。好吧,至少 3.4 是这样。

应该使用来自importlib 模块的reload 函数:

https://docs.python.org/3/library/importlib.html#importlib.reload

但请注意,该库在最后两个次要版本中有一些 API 更改。

【讨论】:

    【解决方案4】:

    如果你想从一个模块中导入一个特定的函数或类,你可以这样做:

    import importlib
    import sys
    importlib.reload(sys.modules['my_module'])
    from my_module import my_function
    

    【讨论】:

    • 我一直在调试模块中包含的辅助函数,该模块还导入了 C/Python api,因此只能通过重新启动内核来重新加载。这让事情变得更快!
    【解决方案5】:

    另一个小点:如果您使用了import some_module as sm 语法,那么您必须使用其别名(在本例中为sm)重新加载模块:

    >>> import some_module as sm
    ...
    >>> import importlib
    >>> importlib.reload(some_module) # raises "NameError: name 'some_module' is not defined"
    >>> importlib.reload(sm) # works
    

    【讨论】:

    • 请注意,这不是一个特殊规则,而是 Python 模块是一流的结果。 import <module> as <name> 语句只是将<name> 分配给模块object。然后reload() 函数接受这个对象。 reload() 函数不关心(或知道)名称。
    • @Quelklef 好点,感谢您的评论。
    【解决方案6】:

    尽管提供的答案确实适用于特定模块,但它们不会重新加载子模块,如 This answer 中所述:

    如果一个模块使用 from ... import ... 从另一个模块导入对象,则为另一个模块调用 reload() 不会重新定义从它导入的对象 — 解决此问题的一种方法是重新执行 from 语句,另一种方法是使用import 和限定名称 (module.*name*) 代替。

    但是,如果使用__all__ 变量来定义公共 API,则可以自动重新加载所有公共可用的模块:

    # Python >= 3.5
    import importlib
    import types
    
    
    def walk_reload(module: types.ModuleType) -> None:
        if hasattr(module, "__all__"):
            for submodule_name in module.__all__:
                walk_reload(getattr(module, submodule_name))
        importlib.reload(module)
    
    
    walk_reload(my_module)
    

    尽管如此,上一个答案中提到的警告仍然有效。值得注意的是,修改__all__ 变量所描述的不属于公共 API 的子模块不会受到使用此函数重新加载的影响。同样,删除子模块的元素不会被重新加载反映。

    【讨论】:

      【解决方案7】:
      import sys
      
      del sys.modules['module_name']
      import module_name
      

      【讨论】:

      • 请添加一些关于代码的解释,它将提供更多信息和帮助:)
      猜你喜欢
      • 2016-04-05
      • 2010-12-19
      • 2011-05-31
      • 2020-08-15
      • 1970-01-01
      • 2018-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多