Python: перезагрузить компонент Y, импортированный с помощью "from X import Y"?
В Python, как только я импортировал модуль X в сеансе интерпретатора, используя import X
, и модуль изменится снаружи, я могу перезагрузить модуль с помощью reload(X)
. Затем изменения становятся доступными в моем сеансе интерпретатора.
Мне интересно, возможно ли это, когда я импортирую компонент Y из модуля X с помощью from X import Y
.
Оператор reload Y
не работает, поскольку Y не является самим модулем, а только компонентом (в данном случае классом) внутри модуля.
Возможно ли вообще перезагрузить отдельные компоненты модуля, не выходя из сеанса интерпретатора (или импортируя весь модуль)?
EDIT:
Для пояснения возникает вопрос об импорте класса или функции Y из модуля X и перезагрузки при изменении, а не модуля Y из пакета X.
Ответы
Ответ 1
Если Y является модулем (и X пакетом) reload(Y)
будет хорошо - в противном случае вы поймете, почему хорошие руководства по стилю Python (например, мой работодатель) говорят никогда импорт ничего кроме модуля (это одна из многих причин, но люди по-прежнему постоянно импортируют функции и классы, независимо от того, насколько я объясняю, что она не хорошая идея, -.)
Ответ 2
Ответ
Из моих тестов. Отмеченный ответ, который предлагает простую reload(X)
, не работает.
Из того, что я могу сказать, правильный ответ:
# python3.x would require
# from importlib import reload
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
Ответ 3
Во-первых, вы не должны использовать перезагрузку вообще, если можете этого избежать. Но предположим, что у вас есть свои причины (т.е. Отладка внутри 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 modulename import func
import sys
reload(sys.modules['modulename'])
from modulename import func
Ответ 5
Если вы хотите сделать это:
from mymodule import myobject
Сделайте это вместо:
import mymodule
myobject=mymodule.myobject
Теперь вы можете использовать myobject так же, как вы планировали (без утомительных нечитаемых ссылок на mymodule везде).
Если вы работаете в интерактивном режиме и хотите перезагрузить myobject из mymodule, вы теперь можете использовать:
reload(mymodule)
myobject=mymodule.myobject
Ответ 6
Предполагая, что вы использовали 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: import в функции) - вы должны использовать вторую версию.
В. если Y импортирован в X из другого модуля (Z) - вы должны перезагрузить Z, а затем перезагрузить X, а затем перезагрузить свой модуль, даже перезагружая все ваши модули (e, g: using [ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ]
) может перезагрузить X до перезагрузки Z - и чем не обновить значение Y.
Ответ 7
-
reload()
модуль X
,
-
reload()
модуль импортирует Y
из X
.
Обратите внимание, что перезагрузка не изменит уже созданные объекты, связанные в других пространствах имен (даже если вы следуете руководству по стилю от Alex).
Ответ 8
Чтобы следить за ответами AlexMartelli и Catskul, есть несколько действительно простых, но неприятных случаев, которые кажется, запутывают 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
вышел из синхронизации с самим собой, что просто странно.
Ответ 9
Если вы работаете в среде jupyter, и у вас уже есть from module import function
может использовать магическую функцию, autoreload
по
%load_ext autoreload
%autoreload
from module import function
Введение в autoreload
в IPython приведено здесь.