重装模块已导入另一个模块

时间:2012-12-23 23:05:58

标签: python import module reload

让我们面对现实,改变它后重新加载python代码的整个过程是一团糟。我想了一下,在解释器上调用import <module>from <module> import <class/function>更好,因为我可以调用reload(module)来获取更新的代码。

但我现在有更复杂的问题。所以我有这个文件,module1.py,并在顶部说:

from module2 import <class1>, <function1>, etc.

然后我去改变module2中的代码。事实证明,调用reload(module1)将不会重新加载module2中更改的代码,即使module2的代码是在module1的顶部导入的。有没有办法在不重新启动解释器的情况下重新加载所有内容?

在有人谈论我的关于风格的案例之前,我只会说:

  1. 我只从解释器中调用reload,而不是在活动代码中。这个问题涉及我正在测试新代码时。
  2. 我从不打电话给<module> import *,我知道这会破坏可读性

6 个答案:

答案 0 :(得分:13)

了解IPython。它具有autoreload扩展,在调用其中的函数之前,在解释器会话期间自动重新加载模块。我引用着陆页中的示例:

In [1]: %load_ext autoreload

In [2]: %autoreload 2

In [3]: from foo import some_function

In [4]: some_function()
Out[4]: 42

In [5]: # open foo.py in an editor and change some_function to return 43

In [6]: some_function()
Out[6]: 43

答案 1 :(得分:10)

要重新加载模块,您必须使用reload,并且必须在要重新加载的模块上使用它。重新加载模块不会递归地重新加载该模块导入的所有模块。它只是重新加载那个模块。

导入模块时,会存储对该模块的引用,稍后该模块的导入将重新使用已导入的已存储版本。当您重新加载module1时,它会重新运行from module2 import ...语句,但只重用已导入的module2版本而不重新加载它。

解决此问题的唯一方法是更改​​代码,使其代替import module2而不是from module2 import ...。除非模块本身已导入并绑定到名称(即使用import module语句,而不仅仅是from module import stuff语句,否则无法重新加载模块。

请注意,您可以使用这两种形式的导入,重新加载导入的模块将影响后续的from导入。也就是说,你可以这样做:

>>> import module
>>> from module import x
>>> x
2
# Change module code here, changing x to 3
>>> reload(module)
>>> from module import x
>>> x
3

这对于交互式工作非常方便,因为它允许您使用简短的,没有前缀的名称来引用您需要的内容,同时仍然可以重新加载模块。

答案 2 :(得分:2)

不是在重新加载模块方面做得更好,而是可以更好地重新启动解释器。例如,您可以将设置代码放入其自己的文件中,然后像下面这样运行:

$ python -i setup.py
>>>

这将运行setup.py,然后让您进入交互式提示。或者,不要在交互式提示中做很多工作,而是编写能够为您完成工作的自动化测试。

你是对的,用Python重新加载模块是一团糟。语言的语义使得在进程运行时更改代码变得困难。学会不需要重新加载模块,你会更快乐。

答案 3 :(得分:2)

好的,我不确定如果没有更改代码就可以作为答案,但至少......不需要更改module1

你可以使用一些模块包装类,它在加载module1之前和之后保存加载的模块,并提供reload方法,类似:

import sys

class Reloader(object):
    def __init__(self, modulename):
        before = sys.modules.keys()
        __import__(modulename)
        after = sys.modules.keys()
        names = list(set(after) - set(before))
        self._toreload = [sys.modules[name] for name in names]

    def do_reload(self):
        for i in self._toreload:
            reload(i)

然后使用:

加载module1
reloader = Reloader('module1')

参考您可以修改module2并在解释器中使用以下命令重新加载:

reloader.do_reload()

答案 4 :(得分:1)

不要忘记导入实际上只是在命名空间中指定名称。因此,您可以在重新加载后重新分配该名称:

>>> reload(module2)
>>> module1.class1 = module2.class1

现在,module1中的class1对象引用了module2的重新加载版本。

答案 5 :(得分:0)

这是一个你可以使用的递归重载函数(归功于@Matthew): https://stackoverflow.com/a/17194836/1020625