2012-12-23 116 views
14

让我们面对它,改变它后重新加载python代码的整个业务是一团糟。我想了一会儿回来,在口译员打电话import <module>from <module> import <class/function>好,因为然后我可以拨打reload(module)获取更新的代码。重新加载模块已导入到另一个模块

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

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

然后我去改代码中模块2。原来,调用reload(module1)将不会重新加载模块2中更改的代码,即使module2的代码是在模块1的顶部导入的。有没有什么方法可以在不重新启动解释器的情况下重新载入一切?

任何人对我的情况下,大约风格得到之前,我只想说的是:

  1. 我只能拨打reload从解释,从未在活动代码。这个问题涉及我测试新代码的时间。
  2. 我从来没有从<module> import *打电话,我知道这会破坏可读性
+1

这里是一个递归重装功能,你可以使用:http://stackoverflow.com/a/17194836/1020625 – AlbertFerras

+0

等待,这是一个非常好的答案。如果您将其作为答案发布,那么我会接受它。 –

+0

完成!谢谢:) – AlbertFerras

回答

10

重新加载模块,你必须使用reload,你必须使用它,你要重新加载模块。重新加载模块不会递归地重新加载该模块导入的所有模块。它只是重新加载一个模块。

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

解决此问题的唯一方法是更改​​您的代码,使其代替(或除from module2 import ...之外)import 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 

这是很方便的交互工作,因为它可以让你使用短,前缀的名字来指你所需要的,同时仍然能够重新加载模块。

+0

为了完整起见,以下是重新加载的参考:http://docs.python.org/2/library/functions.html#reload –

0

不要忘记,导入只是在命名空间中分配一个名称。所以,你可以重装后的重新分配名称:

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

现在内部模块1 class1对象是指从模块2重载版本。

1

与重新加载模块相比,您可以在重新启动解释器时做得更好。例如,你可以把你的设置代码到自己的文件,然后像这样运行它:

$ python -i setup.py 
>>> 

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

你说得对,在Python中重新加载模块是一团糟。语言的语义使得在进程运行时很难更改代码。学习不需要重新加载模块,你会更开心。

+0

有趣的想法,但有时解释器的命令历史记录是有用的。每当你改变你的代码时,你真的会销毁它吗? –

+1

IPython如何?它会保存会话之间的命令历史记录。 – utapyngo

+0

使用'PYTHONSTARTUP'环境变量会更有意义。 @EricWilson,你可以用'readline.read_history_file(“setup.py”)''来读取同样的启动脚本,把所有的命令添加到你的历史记录中。 @utapyngo,你不需要IPython; 'readline'模块提供了以下功能:'atexit.register(readline.write_history_file,hist_file)',其中'hist_file'是你想要包含历史记录的文件的名称。 – 2013-07-01 14:04:48

12

查看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 
+2

谢谢,但我不打算使用IPython或Jython。 –

+1

@EricWilson IPython只是另一个shell,与Jython没有什么共同之处。如果有的话,你可以看看'autoreload'的来源,看看他们是如何做到的。 – davidism

+1

@davidism哦,我想我把IronPython与IPython搞混了。我会仔细看看的。 –

2

好吧,我不知道有资格为在不更改代码的答案,但......至少,不涉及更改module1

你可以使用一些模块包装类,在此之前和加载模块1后保存加载的模块,并提供了一个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) 

然后加载模块1具有:

reloader = Reloader('module1') 

因为您可以修改module2并将其重新加载到解释器中:

reloader.do_reload() 
0

这里,你可以使用(信贷@Matthew)递归重装功能: https://stackoverflow.com/a/17194836/1020625

+0

这并不能解决OP询问的问题。该功能通过查找模块中引用其他模块的所有全局变量来工作。这些将由诸如'import someModule'之类的语句创建。但是,如果你从'某些模块导入某些东西',没有引用模块本身的变量被创建,所以'rreload'函数不会重新加载'someModule'。 – BrenBarn

+0

这是真的,我没有想过 – AlbertFerras

相关问题