2009-11-16 76 views
56

在Python中,一旦我使用import X在解释器会话中导入了模块X,并且模块在外部发生了更改,我可以使用reload(X)重新加载模块。这些更改将在我的口译员会话中提供。Python:重新加载组件Y与'从X导入Y'导入?

我想知道如果这也可以使用from X import Y从模块X导入组件Y.

语句reload Y不起作用,因为Y不是一个模块本身,而只是一个模块内部的一个组件(本例中是一个类)。

是否有可能在不离开解释器会话(或导入整个模块)的情况下重新加载模块的各个组件?

编辑:

为了澄清,问题是关于从包装X.从模块X导入类或函数Y和重装上的改变,而不是一个模块Y

+0

我相信,在这个问题上的矛盾:“'... ...可能从导入模块X'分量Y”与“'问题是......从一个模块Y'导入类或函数X ”。我为此添加了一个编辑。 – Catskul

+0

似乎标记的答案实际上并没有回答这个问题,我相信我的答案。你能更新/评论吗? – Catskul

回答

40

如果Y是一个模块(和X包)reload(Y)将会很好 - 否则,你会看到为什么好的Python风格指南(如我的雇主)说从来没有进口什么除了一个模块(这是一个很多很重要的原因 - 但人们仍然直接导入函数和类,不管我多么解释它是而不是是一个好主意;-)。

+0

我明白你的观点。你是否愿意详细说明为什么它不是一个好主意? – cschol

+5

@cschol:Python的禅,最后一节(从交互式提示中导入这个'来看看Python的禅);和所有的原因_why_命名空间是一个好的想法(直接的本地视觉线索,名称被抬头,在测试中轻松嘲讽/注入,重新加载的能力,模块通过重新定义一些条目灵活改变的能力,可预测和可控在序列化和恢复你的数据方面的行为[例如通过酸洗和取消]等,等等 - 一个SO评论是不够长的公理,这个丰富的,长期的论据!!! - ) –

+0

+ 1为答复,丰富,长期的评论,并提及你的雇主的风格指南。 :) – cschol

1
  1. reload()模块X
  2. reload()模块从X导入Y

请注意,重新加载不会更改已在其他名称空间中绑定的已创建对象(即使您遵循Alex的样式指南)。

7

首先,如果可以避免,则根本不应该使用重新加载。但是让我们假设你有你的理由(即在IDLE中调试)。

重新加载库不会将名称返回到模块的名称空间中。要做到这一点,只需重新分配变量:

f = open('zoo.py', 'w') 
f.write("snakes = ['viper','anaconda']\n") 
f.close() 

from zoo import snakes 
print snakes 

f = open('zoo.py', 'w') 
f.write("snakes = ['black-adder','boa constrictor']\n") 
f.close() 

import zoo 
reload(zoo) 
snakes = zoo.snakes # the variable 'snakes' is now reloaded 

print snakes 

您可以通过其他方法做到这一点。您可以通过搜索本地名称空间来自动执行该过程,并重新分配来自所讨论模块的任何内容,但我认为我们已经足够邪恶了。

55

答案

从我的测试。标记的答案表明简单的reload(X)不起作用。

从我可以告诉正确答案是:

import X 
reload(X) 
from X import Y 

测试

我的测试是以下(Python的2.6.5 + bpython 0.9.5.2)

X .py:

def Y(): 
    print "Test 1" 

bpython:

>>> from X import Y 
>>> print Y() 
Test 1 
>>> # Edit X.py to say "Test 2" 
>>> print Y() 
Test 1 
>>> reload(X) # doesn't work because X not imported yet 
Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
NameError: name 'X' is not defined 
>>> import X 
>>> print Y() 
Test 1 
>>> print X.Y() 
Test 1 
>>> reload(X) # No effect on previous "from" statements 
>>> print Y() 
Test 1 
>>> print X.Y() # first one that indicates refresh 
Test 2 
>>> from X import Y 
>>> print Y() 
Test 2 
>>> # Finally get what we were after 
+0

哇。我发现这非常方便。谢谢!我现在用它作为一个班轮:import X;重新加载(X);从X进口Y – otterb

+0

这是比接受的更好的答案。警告人们是公平的,但每个人的用例都不相同。在某些情况下,重新加载类是非常有帮助的,例如,当您使用python控制台并希望在不丢失会话的情况下加载对代码的更改时。 – nicb

+0

这似乎并不总是有效。我有一个'Foo'模块,它有一个'__init __。py'来获取一个子模块...我会将一个答案作为一个反例。 –

4
from modulename import func 

import sys 
reload(sys.modules['modulename']) 
from modulename import func 
+0

这是最好的方法,因为你可能不记得它是如何导入的 – portforwardpodcast

1

如果你想这样做:

from mymodule import myobject 

而是执行此操作:

import mymodule 
myobject=mymodule.myobject 

您可以用同样的方式,现在将myObject为你规划(无处不在的无法读取的mymodule参考)。

如果你在交互模式下工作,并希望重新从MyModule的MyObject的你现在可以使用:

reload(mymodule) 
myobject=mymodule.myobject 
0

假设你使用from X import Y,你有两个选择:

reload(sys.modules['X']) 
reload(sys.modules[__name__]) # or explicitly name your module 

Y=reload(sys.modules['X']).Y 

很少考虑:

答:如果导入作用域不是模块范围的(例如:在函数中导入) - 您必须使用第二个版本。如果Y从另一个模块(Z)导入到X中,则必须重新加载Z,而不是重新加载X并重新加载模块,即使重新加载所有模块(例如使用[ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ])可能会在之前重新加载X重装ž - 比不刷新Y.

的价值
0

只是跟进AlexMartelli'sCatskul's答案,还有一些出现混淆reload,至少在Python 2

很简单,但讨厌的情况下,假设我有以下源代码树:

- foo 
    - __init__.py 
    - bar.py 

具有以下内容:

init.py:

from bar import Bar, Quux 

吧。潘岳:

print "Loading bar" 

class Bar(object): 
    @property 
    def x(self): 
    return 42 

class Quux(Bar): 
    object_count = 0 
    def __init__(self): 
    self.count = self.object_count 
    self.__class__.object_count += 1 
    @property 
    def x(self): 
    return super(Quux,self).x + 1 
    def __repr__(self): 
    return 'Quux[%d, x=%d]' % (self.count, self.x) 

这一切正常,而无需使用reload

>>> from foo import Quux 
Loading bar 
>>> Quux() 
Quux[0, x=43] 
>>> Quux() 
Quux[1, x=43] 
>>> Quux() 
Quux[2, x=43] 

但尝试重新加载,它要么没有效果或破坏的东西:

>>> import foo 
Loading bar 
>>> from foo import Quux 
>>> Quux() 
Quux[0, x=43] 
>>> Quux() 
Quux[1, x=43] 
>>> reload(foo) 
<module 'foo' from 'foo\__init__.pyc'> 
>>> Quux() 
Quux[2, x=43] 
>>> from foo import Quux 
>>> Quux() 
Quux[3, x=43] 
>>> reload(foo.bar) 
Loading bar 
<module 'foo.bar' from 'foo\bar.pyc'> 
>>> Quux() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "foo\bar.py", line 17, in __repr__ 
    return 'Quux[%d, x=%d]' % (self.count, self.x) 
    File "foo\bar.py", line 15, in x 
    return super(Quux,self).x + 1 
TypeError: super(type, obj): obj must be an instance or subtype of type 
>>> Quux().count 
5 
>>> Quux().count 
6 
>>> Quux = foo.bar.Quux 
>>> Quux() 
Quux[0, x=43] 
>>> foo.Quux() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "foo\bar.py", line 17, in __repr__ 
    return 'Quux[%d, x=%d]' % (self.count, self.x) 
    File "foo\bar.py", line 15, in x 
    return super(Quux,self).x + 1 
TypeError: super(type, obj): obj must be an instance or subtype of type 
>>> foo.Quux().count 
8 

只有我能方式确保bar子模块重新加载到reload(foo.bar);我访问重新加载Quux类的唯一方法是到达并从重新加载的子模块中抓取;但foo模块自身保持保持到原始Quux类对象,大概是因为它使用from bar import Bar, Quux(而不是import bar随后Quux = bar.Quux);此外,Quux类与它本身不同步,这是奇怪的。

相关问题