Python 重新加载已导入到其他模块的模块
让我们面对它,在修改python代码后重新加载它的整个过程是一团混乱。不久前我发现在解释器中调用Python 重新加载已导入到其他模块的模块,python,import,module,reload,Python,Import,Module,Reload,让我们面对它,在修改python代码后重新加载它的整个过程是一团混乱。不久前我发现在解释器中调用import比从import调用要好,因为这样我就可以调用reload(module)来获取更新的代码 但我现在有更复杂的问题。我有一个文件module1.py,上面写着: from module2 import <class1>, <function1>, etc. 来自模块2导入等的。 然后我去修改模块2中的代码。结果表明,调用reload(module1)不会重新加载
import
比从import调用要好,因为这样我就可以调用reload(module)
来获取更新的代码
但我现在有更复杂的问题。我有一个文件module1.py,上面写着:
from module2 import <class1>, <function1>, etc.
来自模块2导入等的。
然后我去修改模块2中的代码。结果表明,调用reload(module1)
不会重新加载module2中更改的代码,即使来自module2的代码是在module1的顶部导入的。有没有办法在不重新启动解释器的情况下重新加载所有内容
在任何人开始谈论我的风格之前,我只想说:
我只从解释器调用reload
,从不在活动代码中调用。这个问题与我测试新代码时有关
我从不从import*
调用,我知道这会破坏可读性
要重新加载模块,必须使用重新加载
,并且必须在要重新加载的模块上使用它。重新加载模块不会递归地重新加载该模块导入的所有模块。它只是重新加载一个模块
导入模块时,将存储对该模块的引用,该模块的后续导入将重新使用已导入、已存储的版本。重新加载module1
时,它会重新运行from module2 import…
语句,但只会重用已导入的module2
版本,而不会重新加载
解决此问题的唯一方法是更改您的代码,使其能够导入module2
,而不是(或除了)从module2导入…
。除非模块本身已导入并绑定到名称(即,使用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
这对于交互式工作非常方便,因为它允许您使用简短、不固定的名称来引用所需内容,同时仍然能够重新加载模块。不要忘记导入实际上只是在命名空间中分配名称。因此,您可以在重新加载后重新分配该名称:
>>> reload(module2)
>>> module1.class1 = module2.class1
现在module1中的class1
对象指的是从module2重新加载的版本。重新加载模块不是更好,而是更好地重新启动解释器。例如,您可以将安装代码放入自己的文件中,然后按如下方式运行:
$ python -i setup.py
>>>
这将运行setup.py,然后在交互式提示下离开您。或者,与其在交互式提示中做大量工作,不如编写自动测试来为您完成工作
您是对的,在Python中重新加载模块是一个混乱。该语言的语义使得在进程运行时很难更改代码。学会不需要重新加载模块,你会更快乐。看看IPython。它有一个扩展,可以在解释器会话期间,在调用内部函数之前自动重新加载模块。我引用登录页上的例子:
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
的更改
您可以使用一些模块包装器类,该类在加载模块1之前和之后保存加载的模块,并提供一个重新加载
方法,类似于:
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)
然后,用以下各项加载模块1:
reloader = Reloader('module1')
请注意,您可以使用以下命令修改模块2并将其重新加载到解释器中:
reloader.do_reload()
下面是一个可以使用的递归重载函数(归功于@Matthew):
这个想法很有趣,但有时解释器的命令历史记录很有用。你真的每次修改代码都会破坏它吗?IPython呢?它在会话之间保存命令历史记录。使用PYTHONSTARTUP
环境变量更有意义@EricWilson,您可以使用readline.read\u history\u文件(“setup.py”)
读取相同的启动脚本,将所有命令添加到历史记录中@乌塔平戈,你不需要伊皮顿;readline
模块提供该功能:atexit.register(readline.write_history_file,hist_file)
,其中hist_file
是您希望包含历史的文件的名称。谢谢,但我不会使用IPython或Jython。我很高兴在这里奖励奖金,因为发现IPython的价值远远超过50次。谢谢。这里有一个递归重载函数,你可以使用:等等,这是一个非常好的答案。如果您将其作为答案发布,我将接受。这不会满足您对模块导入内容的要求。请看我对答案的评论。这并不能解决OP提出的问题。该函数通过查找模块中引用其他模块的所有全局变量来工作。这些将由诸如import someModule
之类的语句创建。但是,如果您从someModule导入一些内容,则不会创建引用模块本身的变量,因此,rreload
函数将不会重新加载someModule
。确实如此,为了完整性,我没有考虑它,这里是重新加载的参考: