Python: перезагрузить компонент Y, импортированный с помощью 'from X import Y'?
в Python, как только я импортировал модуль X в сеанс интерпретатора с помощью import X
, и модуль меняется снаружи, я могу перезагрузить модуль с reload(X)
. Затем изменения становятся доступными в моем сеансе интерпретатора.
мне интересно, возможно ли это также, когда я импортирую компонент Y из модуля X с помощью from X import Y
.
заявление reload Y
не работает, так как Y-это не сам модуль, а только компонент (в данном случае класс) внутри a модуль.
можно ли вообще перезагрузить отдельные компоненты модуля, не выходя из сеанса интерпретатора (или импортируя весь модуль)?
EDIT:
для уточнения, вопрос об импорте класс или функция Y С модуль X и перезагрузка на изменение, а не модуль Y из пакета X.
8 ответов:
если Y-модуль (а X-пакет)
reload(Y)
будет хорошо - в противном случае вы увидите, почему хорошие руководства по стилю Python (например, мой работодатель) говорят никогда импортировать что-либо за исключением модуль (это одна из многих великих причин-но люди все еще продолжают импортировать функции и классы напрямую, независимо от того, сколько я объясняю, что это не хорошая идея;-).
ответ
из моих тестов. Отмеченный ответ, который предполагает простой
reload(X)
, не работает.из того, что я могу сказать правильный ответ:
import X reload( X ) from X import Y
тест
мой тест был следующим (Python 2.6.5 + bpython 0.9.5.2)
Х. ру:
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
во-первых, вы не должны использовать перезагрузку вообще, если вы можете избежать этого. Но давайте предположим, что у вас есть свои причины (т. е. отладка внутри 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
вы могли бы сделать это несколько другими способами. Вы можете автоматизировать процесс, выполнив поиск в локальном пространстве имен и переназначив все, что было из рассматриваемого модуля, но я думаю, что мы они достаточно злые.
from modulename import func import sys reload(sys.modules['modulename']) from modulename import func
Если вы хотите сделать это:
from mymodule import myobject
вместо этого:
import mymodule myobject=mymodule.myobject
Теперь вы можете использовать myobject так же, как вы планировали (без утомительных нечитаемых ссылок на mymodule везде).
Если вы работаете в интерактивном режиме и хотите перезагрузить myobject из mymodule теперь вы можете использовать:
reload(mymodule) myobject=mymodule.myobject
reload()
модульX
,reload()
модуль импортаY
СX
.обратите внимание, что перезагрузка не изменит уже созданные объекты, связанные в других пространствах имен (даже если вы следуете руководству по стилю от Alex).
если вы использовали
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 импортируется в X из другого модуля (Z) - вы должны перезагрузить Z, чем перезагрузить X и чем перезагрузить ваш модуль, даже перезагрузить все ваши модули (например,используя
[ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ]
) может перезагрузить X перед перезагрузкой Z - и чем нет обновить значение Y.
в связи с AlexMartelli это и Catskul это!--18--> ответы, есть некоторые действительно простые, но неприятные случаи, которые, кажется, смущают
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
класс вышел из синхронизации с самим собой, что просто странно.