Как изменить переменную модуля из другого модуля?

Предположим, у меня есть пакет с именем 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

Может кто-нибудь объяснить мое заблуждение?

85
задан Antti Haapala 10 March 2016 в 13:20
поделиться

2 ответа

Вы используете из импортированной полосы . 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 . Изменение точки, на которую указывает символ, также не меняет значение, на которое он указывает.

Подобные вещи убивают при попытке перезагрузить модуль из интерактивного интерпретатора.

82
ответ дан 24 November 2019 в 08:23
поделиться

Одна из причин трудностей с этим вопросом заключается в том, что у вас есть программа с именем 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 импортирует в __ init __. Py связывает имя bar / __ init__.py:a с исходным bar.py:a ( Нет ). Вот почему вы можете выполнить from bar import a as a2 в __ init __. Py : в этом случае очевидно, что у вас есть оба bar / bar.py: a и отдельное имя переменной bar / __ init__.py:a2 (в вашем случае имена двух переменных просто совпадают с a , но они по-прежнему находятся в разных пространствах имен: в __ init __. py это bar.a и a ).

Теперь, когда вы выполняете

import bar

print bar.a

, вы получаете доступ к переменной bar / __ init__.py:a (поскольку import bar импортирует ваш bar / __ init __. Py ]). Это переменная, которую вы изменяете (на 1). Вы не трогаете содержимое переменной bar / bar.py: a .Поэтому, когда вы впоследствии выполняете

bar.foobar()

, вы вызываете bar / bar.py: foobar () , который обращается к переменной a из bar / bar.py , которая по-прежнему Нет (когда foobar () определен, он связывает имена переменных раз и навсегда, поэтому a в bar.py - это bar.py:a , а не какая-либо другая a переменная, определенная в другом модуле - поскольку может быть много a переменных во всех импортированных модулях). Следовательно, последний вывод None .

19
ответ дан 24 November 2019 в 08:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: