Python: reload component Y imported with 'from X import Y'?

在 Python 中,一旦我使用 import X在解释器会话中导入了模块 X,并且模块在外部发生了变化,我就可以使用 reload(X)重新加载模块。然后,这些更改在我的解释器会话中可用。

当我使用 from X import Y从模块 X 导入组件 Y 时,我想知道这是否也是可能的。

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

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

编辑:

澄清一下,这个问题是关于从 模组 X导入 类或函数并重新加载更改,而不是从包 X 中重新加载模块 Y。

57717 次浏览

如果 Y 是一个模块(X 是一个包) ,那么 reload(Y)就没问题——否则,你就会明白为什么好的 Python 风格指南(比如我雇主的指南)会说 永远不会导入任何东西 除了就是一个模块(这是许多重要原因中的一个——然而人们仍然直接导入函数和类,不管我怎么解释它是 没有是一个好主意;)。

  1. reload()模块 X,
  2. X导入 Yreload()模块。

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

首先,如果可以避免的话,根本就不应该使用 reload。但是,让我们假设您有自己的理由(即在 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

你可以用其他方法。您可以通过搜索本地名称空间并重新分配所涉及的模块中的任何内容来自动化这个过程,但是我认为我们已经够邪恶的了。

回答我

根据我的测试,标记的答案,即建议一个简单的 reload(X),没有工作。

据我所知,正确答案是:

from importlib import reload # python 2.7 does not require this
import X
reload( X )
from X import Y

Test

我的测试如下(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
from modulename import func


import importlib, sys
importlib.reload(sys.modules['modulename'])
from modulename import func

如果你想这样做:

from mymodule import myobject

不如这样做:

import mymodule
myobject=mymodule.myobject

现在,您可以按照计划的方式使用 myobject (没有到处都是无法阅读的令人厌烦的 mymodule 引用)。

If you're working interactively and want to reload myobject from mymodule you now can using:

reload(mymodule)
myobject=mymodule.myobject

假设您使用的是 from X import Y,您有两个选择:

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

或者

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

几点考虑:

如果导入范围不是模块范围的(e,g: 函数中的导入) ,则必须使用第二个版本。

如果 Y 是从另一个模块(Z)导入到 X 中的-你必须重新加载 Z,然后重新加载 X,然后重新加载你的模块,甚至重新加载你所有的模块(e,g: 使用 [ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ])可能在重新加载 Z 之前重新加载 X,然后不刷新 Y 的值。

仅仅跟踪 AlexMartelli 的Catskul 的的答案,就会发现有一些非常简单但令人讨厌的情况似乎让 reload感到困惑,至少在 Python 2中是这样。

Suppose I have the following source tree:

- foo
- __init__.py
- bar.py

内容如下:

init.py:

from bar import Bar, Quux

Bar.py:

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类与它自己不同步,这很奇怪。

如果你在木星环境下工作,并且你已经有了 from module import function可以使用的神奇功能,autoreload

%load_ext autoreload
%autoreload
from module import function

The introduction of the autoreload in IPython is given 给你.