Подтвердить что ты не робот

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().

4b9b3361

Ответ 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 определенным образом.