2012-07-23 5 views
3

Есть много вопросов и ответов относительно повторного импорта на SO, но все это кажется очень противоречивым, не зная механизмов, стоящих за ним.Почему вы не можете повторно импортировать Python?

Если импортировать модуль, изменять содержимое, а затем попытаться импортировать его снова, вы увидите, что второй импорт не имеет никакого эффекта:

>>> import foo # foo.py contains: bar = 'original' 
>>> print foo.bar 
original 
>>> # edit foo.py and change to: bar = 'changed' 
>>> import foo 
>>> print foo.bar 
original 

Я была очень счастлива автофургоне, когда я обнаружил reload :

>>> reload(foo) 
>>> print foo.bar 
changed 

Однако нет простого решения, когда вы импортируете элементы из модуля без импорта самого модуля:

>>> from foo import baz 
>>> print baz 
original 
>>> # change foo.py from baz = 'original' to baz = 'changed' 
>>> from foo import baz 
>>> print baz 
original 
>>> reload(foo) 
Traceback (most recent call last): 
    File "<pyshell#10>", line 1, in <module> 
    reload(foo) 
NameError: name 'foo' is not defined 

Почему Python не обновляет импортированные элементы, когда вы даете ему новый оператор import?

+0

Если вы хотите, чтобы система автозагрузки á la PHP в вашей системе Python рассматривала fork-loop: http://opensourcehacker.com/2011/11/08/sauna-reload-the-most-awesomely-named- python-package-ever/ –

+0

@MikkoOhtamaa, мой прецедент, приводящий к вопросу, отличается, в частности, обновление и тестирование модуля с интерактивного сеанса. В этом интерактивном сеансе есть данные, которые я не хочу выбрасывать. –

ответ

10

При импорте модуля он кэшируется в sys.modules. Любая попытка импортировать тот же самый модуль снова в тот же сеанс просто возвращает уже существующий модуль, содержащийся там. Это ускоряет общий опыт, когда модуль импортируется из нескольких мест. Он также позволяет модулю иметь свои собственные объекты, разделяемые между всеми импортами, поскольку каждый раз возвращается тот же модуль.

Как уже упоминалось, вы можете использовать reload для повторного импорта всего модуля. Проверьте документацию на наличие оговорок, потому что даже это не является безупречным.

При импорте определенных элементов из модуля весь модуль импортируется, как указано выше, а затем запрошенные объекты помещаются в пространство имен. reload не работает, потому что эти объекты не являются модулями, и вы никогда не получали ссылку на сам модуль. Обходной получить ссылку на модуль, загрузите его, а затем повторно импортировать:

>>> from foo import baz 
>>> print baz 
original 
>>> # change foo.py from baz = 'original' to baz = 'changed' 
>>> import foo 
>>> reload(foo) 
>>> from foo import baz 
>>> print baz 
changed 
2

простое объяснение «почему» является то, что операторы импорта связаны две операции: загрузка модуля (т.е. работает код внутри него) и импортирование имен в пространство имен модуля импорта. Повторный импорт только повторяет вторую операцию. Причина в том, что первая операция может быть дорогостоящей с точки зрения вычислений и ресурсов памяти.

reload предоставляется как способ повторить первую операцию, но, как вы видели, для этого требуется имя модуля. Не обманывайте себя, однако, полагая, что from foo import bar не загрузить весь модуль. Оно делает. Весь код модуля запущен, просто вы можете обратиться к именам (например, bar), которые вы явно импортируете. По этой причине существует незначительная разница между импортом модуля, а не импортом; единственными отличиями являются проблемы пространства имен. Поэтому, если вы считаете, что можете перезагрузить модуль foo, вы должны пойти дальше и сделать import foo. Если вы хотите, вы можете сделать это, чтобы обновить импортированные имена:

import foo 
from foo import bar 
# later... 
reload(foo) 
from foo import bar 

Там еще одна причины, вы не можете реимпорт отдельных имен, которые в том, что Python не имеют никакого способа изменения объектов называются; он может только переименовывать имена.Предположим, что вы делаете это:

from foo import bar 
newBar = bar 
from foo import bar 

Даже если второй импорт действительно обновить значение бара, он никогда не может обновить значение newBar, потому что ни Foo, ни бар имеет никакого способа узнать, что вы создали дополнительное имя для обозначения бара. Избегание перезаписи отдельных имен не позволяет вам попасть в эту ловушку; если бы люди думали, что реимпорт будет обновлять имена, было бы легко забыть, что он все равно не обновит объекты.

Смежные вопросы