Python:重新加载用'from X import Y'导入的组件Y?


91

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

我想知道当我使用从模块X导入组件Y时是否也可行from X import Y

该语句reload Y不起作用,因为Y本身不是模块,而是模块内部的仅组件(在这种情况下为类)。

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

编辑:

为了澄清起见,问题是关于从模块X导入类或函数Y并在更改时重新加载,而不是从包X重新加载模块Y。


我相信在这个问题上有一个矛盾:“ ... possible ... import a component Y from module X” vs“ question is ... importing a class or function X from a module Y”。我为此添加了一个编辑。
Catskul 2012年

我相信我的答案似乎是标记的答案实际上并未回答问题。您可以更新/评论吗?
Catskul

Answers:


49

如果Y是一个模块(而X是一个包)reload(Y)就可以了-否则,您将明白为什么优秀的Python样式指南(例如,我的老板的)会说除了模块之外不要导入任何东西(这是许多重要原因之一) -但是人们仍然继续直接导入函数和类,无论我解释多少,这都不是个好主意;-)。


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

6
@cschol:Python的Zen,最后一节(import this从交互式提示中查看Python的Zen);以及为什么命名空间是一个很棒的主意的所有原因(立即在本地直观的线索中显示了该名称,易于模拟/注入测试,重新加载的能力,通过重新定义一些条目(可预测和可控制)灵活更改模块的能力序列化和恢复数据的行为[[例如,通过酸洗和解酸],等等,依此类推-SO注释的时间不足以使这个丰富而冗长的论点公道!!!)
Alex Martelli

4
请注意,在Python 3中,重载不再位于默认名称空间中,而是已移至importlib包中。 importlib.reload(Y) docs.python.org/3.4/library/…另请参阅stackoverflow.com/questions/961162/…–

4
@ThorSummoner,绝对不是-它的意思是“总是导入MODULES”,所以“从my.package import mymodule”是绝对好的,并且确实是首选-只是,从不导入类,函数等-始终,仅,永远模块
Alex Martelli

2
下注。为什么?这不是正确的答案。Catskul在2012年7月30日15:04给出了正确的答案。
meh

102

回答

根据我的测试,标记为简单的答案reload(X)是行不通的。

从我可以看出的正确答案是:

from importlib import reload # python 2.7 does not require this
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

1
哇。我发现这真的很方便。谢谢!我现在将其用作一个班轮:导入X;重新加载(X); 从X进口Y
otterb 2014年

1
这是一个比公认的更好的答案。警告人们是公平的,但是每个人的用例都不同。在某些情况下,重新加载类确实很有帮助,例如,当您使用python控制台并希望将更改加载到代码而又不会丢失会话时。
nicb

这似乎并不总是有效。我有一个模块Foo,其中有一个__init__.py可获取子模块的模块...我将发布一个答案作为反例。
杰森·S

Python 3现在一个内衬:import importlib; import X; importlib.reload(X); 从X进口Y
韦恩

12
from modulename import func

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

这是imo的最佳方法,因为您可能不记得确切地是如何导入的
portforwardpodcast

这是原始问题的唯一可行解决方案,票数太少!
CharlesB

1
在python 3中添加:从importlib导入重新加载
mirek

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

您可以通过其他几种方式执行此操作。您可以通过搜索本地名称空间并重新分配来自所讨论模块的任何内容来自动化该过程,但是我认为我们已经足够邪恶了。


4

如果要这样做:

from mymodule import myobject

改为这样做:

import mymodule
myobject=mymodule.myobject

现在,您可以以与计划相同的方式使用myobject(无需到处都是烦人的,难以理解的mymodule引用)。

如果您正在交互工作,并且想要从mymodule重新加载myobject,现在可以使用:

reload(mymodule)
myobject=mymodule.myobject

2

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

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

要么

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

一些注意事项:

A.如果导入范围不在模块范围内(例如,在函数中导入)-您必须使用第二个版本。

B.如果Y是从另一个模块(Z)导入到X中的,则-您必须重新加载Z,而不是重新加载X并重新加载模块,即使重新加载所有模块(例如使用[ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ])也可能在重新加载Z之前重新加载X-并且不刷新Y的值。



1

如果你在一个jupyter环境中工作,并且已经有from module import function可以使用神奇的功能,autoreload

%load_ext autoreload
%autoreload
from module import function

autoreloadIPython中的介绍在这里给出。


0

只是为了跟进AlexMartelliCatskul的答案,有些真正简单但令人讨厌的案例似乎令人困惑reload至少在Python 2中,。

假设我有以下源代码树:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.