让我们面对现实,改变它后重新加载python代码的整个过程是一团糟。我想了一下,在解释器上调用import <module>
比from <module> import <class/function>
更好,因为我可以调用reload(module)
来获取更新的代码。
但我现在有更复杂的问题。所以我有这个文件,module1.py,并在顶部说:
from module2 import <class1>, <function1>, etc.
然后我去改变module2中的代码。事实证明,调用reload(module1)
将不会重新加载module2中更改的代码,即使module2的代码是在module1的顶部导入的。有没有办法在不重新启动解释器的情况下重新加载所有内容?
在有人谈论我的关于风格的案例之前,我只会说:
reload
,而不是在活动代码中。这个问题涉及我正在测试新代码时。<module> import *
,我知道这会破坏可读性答案 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)
然后使用:
加载module1reloader = 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