Как изменить переменную модуля из другого модуля?
Предположим, у меня есть пакет с именем bar, и он содержит bar.py:
a = None
def foobar():
    print a
и __init__.py:
from bar import a, foobar
затем я выполняю этот скрипт:
import bar
print bar.a
bar.a = 1
print bar.a
bar.foobar()
вот что я ожидаю:
None
1
1
вот что я получаю:
None
1
None
может ли кто-нибудь объяснить мое заблуждение?
3 ответа:
вы используете
from bar import a.aстановится символом в глобальной области модуля импорта (или любой области, в которой выполняется оператор импорта). Поэтому, когда вы присваиваете новое значениеa, вы просто измените значениеaочки тоже, а не фактическое значение. попробуйте импортироватьbar.pyнепосредственно сimport barна__init__.pyи провести свой эксперимент, установивbar.a = 1. Таким образом, вы фактически изменяетеbar.__dict__['a']что является "реальным" значениемaв этом контекст.это немного запутанный с тремя слоями, но
bar.a = 1изменяет значениеaв модуле под названиемbarчто на самом деле происходит от__init__.py. Он не изменяет значениеaчтоfoobarвидит, потому чтоfoobarживет в реальном файлеbar.py. Вы можете установитьbar.bar.aесли вы хотите это изменить.это одна из опасностей использования
from foo import barформыimportзаявление: он расщепляетbarв два символа, один виден в глобальном масштабе вfooкоторый начинает указывать на исходное значение и другой символ, видимый в области, гдеimportинструкция выполняется. Изменение a там, где символ указывает, не изменяет значение, на которое он указал.такого рода вещи являются убийцей при попытке
reloadмодуль из интерактивного интерпретатора.
одним из источников трудностей с этим вопросом является то, что у вас есть программа с именем
bar/bar.py:import barимпорт либоbar/__init__.pyилиbar/bar.pyв зависимости от того, где это сделано, что делает его немного громоздким, чтобы отслеживать, какиеaиbar.a.вот как это работает:
ключ к пониманию того, что происходит, чтобы понять, что в вашей
__init__.py,from bar import aпо сути делает что-то вроде
a = bar.a # … with bar = bar/bar.py (as if bar were imported locally from __init__.py)и определяет новую переменную (
bar/__init__.py:a, если вы хотите). Таким образом, вашfrom bar import aна__init__.pyперсонализация имяbar/__init__.py:aв оригинале
поставить другим способом: Оказывается, это заблуждение очень легко сделать. это исподтишка, определенные в языке Python справочник по языку: использование объект вместо символ. Я бы предложил, чтобы ссылка на язык Python сделала это более ясным и менее разреженным..
The
fromформа не связывает имя модуля: он проходит через список идентификаторов, ищет каждый из них в модуле, найденном в шаг (1), и связывает имя в локальном пространстве имен с объект таким образом найдено.:
при импорте вы импортируете текущее значение импортированного символа и добавляете его в пространство имен, как определено.вы не импортируете ссылку, вы фактически импортируете значение.
таким образом, чтобы получить обновленное значение
i, необходимо импортировать переменную, содержащую ссылку к этому символу.другими словами, импорт не похож на
importв JAVA,externalобъявление в C / C++ или даже auseпредложение в PERL.скорее, следующее утверждение в Python:
from some_other_module import a as xбольше как следующий код в K&R C:
extern int a; /* import from the EXTERN file */ int x = a;(предостережение: в случае Python "a" и " x " по существу являются ссылкой на фактическое значение: вы не копируете INT, вы копируете ссылочный адрес)