Как изменить переменную модуля из другого модуля?
Предположим, у меня есть пакет с именем 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, вы копируете ссылочный адрес)