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 64

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
  1. reload() модуль X,
  2. 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 класс вышел из синхронизации с самим собой, что просто странно.