Python: обмен глобальными переменными между модулями и классами в нем
Я знаю, что можно использовать глобальную переменную для модулей в Python. Однако я хотел бы знать, насколько это возможно и почему. Например,
global_mod.py
x = None
mid_access_mod.py
from global_mod import *
class delta:
def __init__(self):
print x
bot_modif_mod.py
import mid_access_mod
import global_mod
class mew:
def __init__(self):
global_mod.x = 5
def main():
m = mew()
d = mid_access_mod.delta()
Отпечатывает None, хотя все модули используют глобальную переменную x. Почему это так? Похоже, что x оценивается на mid_access_mod.py, прежде чем он будет назначен в bot_modif_mod.py с помощью mew().
Ответы
Ответ 1
Это происходит потому, что вы используете неизменяемые значения (ints и None), а импорт переменных - это передача вещей по значению, а не передача данных по ссылке.
Если вы сделали global_mod.x список и обработали его первый элемент, он будет работать так, как вы ожидаете.
Когда вы выполняете from global_mod import x
, вы создаете в своем модуле имя x
с тем же значением, что и x
в global_mod
. Для таких вещей, как функции и классы, это работает так, как вы ожидали бы, потому что люди (как правило) не переустанавливают эти имена позже.
Как указывает Алекс, если вы используете import global_mod
, а затем global_mod.x
, вы избежите проблемы. Имя, которое вы определяете в своем модуле, будет global_mod
, которое всегда относится к модулю, который вы хотите, а затем, используя доступ к атрибуту, чтобы получить в x
, вы получите самое последнее значение x
.
Ответ 2
from whatever import *
не хорошая идиома для использования в вашем коде - она предназначена для использования, если вообще когда-либо, в интерактивном сеансе как ярлык для сохранения некоторой типизации. Это в основном "моментальные снимки" всех имен из модуля в тот момент времени - если вы когда-либо перепроверяете какое-либо из этих имен, моментальный снимок будет устаревать, и возникнут всевозможные проблемы. И это только начало неразрывного беспорядка, с которым вы подписываетесь, используя жалкую конструкцию from ... import *
.
Хотите мой совет? Забудьте, что вы когда-либо слышали о существовании этой конструкции и никогда, никогда не используете ее снова. Используйте import global_mod as m
и всегда используйте квалифицированные имена, такие как m.x
- квалифицированные имена , поэтому гораздо удобнее и мощнее в Python, чем просто имена файлов, "Даже смешно. (as m
часть инструкции import
является полностью необязательной и в основном существует для краткости целей или иногда для решения некоторых проблем с именами конфликтов, использовать ее, когда и если вы считаете ее удобной, поскольку она не имеет недостатков, но не чувствуйте себя принужденными или даже принуждаемыми к использованию, если вы не считаете нужным).
Ответ 3
Я изменил пример, чтобы использовать список для x, и список назначает (x [0] =..), как предложено в верхнем ответе, и печать вернула то же начальное значение (None). Это проверяет, что "from global_mod import *" - это копия, независимо от изменяемой или нет.
Как указано в комментарии, "import global_mod" работает, если "print global_mod.x =" используется в mid_access_mod.
Ответ 4
Как упоминал Нед Батчелдер, только значения разделяются, а не фактический объект. Если вы хотите поделиться объектом по ссылке, то вы, вероятно, смотрите Thread-Local Data
.
Например:
import threading
g = threading.local()
g.population = '7 Billion'
Теперь, когда вы хотите получить доступ или изменить переменную g.population, вы получите обновленное ее значение, если это тот же поток, к которому вы пытаетесь получить доступ.
Подробнее в документации Python: https://docs.python.org/3/library/threading.html#thread-local-data
Ответ 5
Чтобы решить эту проблему, просто измените from global_mod import *
на import global_mod
.
И новый mid_access_mod.py будет:
import global_mod
class delta:
def __init__(self):
print global_mod.x
Причину этого можно найти здесь.
Из-за того, как ссылки и привязка имен работают на Python, если вы хотите обновить некоторый символ в модуле, скажем, foo.bar, из-за пределов этого модуля, а другой код импорта "видеть" это изменение, вы должны import foo определенным образом.