重新加载使用“from X import Y”导入的组件Y

问题描述 投票:0回答:9

在 Python 中,一旦我使用

import X
在解释器会话中导入了模块 X,并且该模块在外部发生更改,我可以使用
reload(X)
重新加载该模块。然后,这些更改将在我的口译员会话中可用。

我想知道当我使用

from X import Y
从模块 X 导入组件 Y 时这是否也可能。

语句

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

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

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

python python-import
9个回答
142
投票

回答

根据我的测试,标记的答案(建议简单的

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

56
投票

如果 Y 是一个模块(而 X 是一个包)

reload(Y)
就可以了——否则,你会明白为什么好的 Python 风格指南(比如我雇主的)说 从不导入任何东西 除了模块(这是众多重要原因之一——但人们仍然继续直接导入函数和类,无论我如何解释这不是一个好主意;-)。


29
投票
from modulename import func

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

6
投票

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

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


5
投票

如果你在jupyter环境中工作,并且你已经有了

from module import function
可以使用魔法功能,
autoreload
by

%load_ext autoreload
%autoreload
from module import function

这里
给出了IPython中autoreload的介绍。


4
投票

如果你想这样做:

from mymodule import myobject

改为这样做:

import mymodule
myobject=mymodule.myobject

您现在可以按照您计划的方式使用 myobject(无需到处都是令人厌烦的、不可读的 mymodule 引用)。

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

reload(mymodule)
myobject=mymodule.myobject

3
投票

假设您使用了

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
投票
  1. reload()
    模块
    X
    ,
  2. reload()
    模块从
    Y
    导入
    X

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


1
投票

只是为了跟进 AlexMartelli'sCatskul's 的答案,有一些非常简单但令人讨厌的情况似乎令人困惑

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

© www.soinside.com 2019 - 2024. All rights reserved.