Первое: Python не имеет реальных глобалов, только глобалы уровня модуля - каждый модуль является отдельным пространством имен, а глобальный является только «глобальным» для модуля, в котором он определен.
Второе:оператор import
не похож на C или PHP include
- он не «копирует» весь импортируемый модуль в импортирующий, но загружает импортированный модуль (если он еще не был загружен) и создает егодоступно в импортируемом пространстве имен
На самом деле это:
import so
- это сокращение для
from importlib import importmodule
so = importmodule("so")
и это:
from so import profit_benchmark
- этоярлык для
from importlib import importmodule
so = importmodule("so")
profit_benchmark = so.profit_benchmark
del so
Как кратко пояснил Джуанпа, во втором случае происходит то, что вы получаете два имени (so.profit_benchmark
и your_importing_module.profit_benchmark
), оба из которых указывают на один и тот же объект.
Теперь переменные Python не являются ячейкой памяти в стиле C, они представляют собой записи name => объекта в пространстве имен (в основном, пары ключ: значение в dict). На самом деле присваивание просто делает назначенную именованную точку другим объектом, поэтому при выполнении
from so import profit_benchmark
profit_benchmark = 42
первый оператор создает имя "profit_benchmark" в текущем пространстве имен и связывает его с тем жеобъект как то, на что указывает so.profit_benchmark
, а второй оператор связывает текущее пространство имен profit_benchmark
name с объектом 42
int, , оставляя so.profit_benchmark
полностью неизменным . Все это (и многое другое очень полезное для понимания) подробно объясняется в этой статье Неда Батчелдера .
С другой стороны, когда вы делаете
import so
so.profit_benchmark = 42
имя, которое вы привязываете, фактически so
'global' profit_benchmark
- которое фактически стало атрибутом объекта модуля so
(во время выполнения модули тоже являются объектами), поэтому любой другой модуль читает so.profit_benchmark
теперь получит обновленное значение.
Как говорится : вы попросили "pythonic way", и pythonic способ на самом деле избежать изменяемого глобального состояния в максимально возможной степени (иэто одна из причин, почему "глобалы" в Python не являются действительно глобальными). И дело в том, что как только вы привыкнете использовать как можно больше чистых функций и классов, когда вам нужно иметь общее состояние some для состояния функций, вы понимаете, что можете писать очень большие программы безодин «доступный для записи» глобальный объект (nb: глобалы, предназначенные только для чтения, конечно, в порядке, проблемы начинаются, когда вы начинаете мутировать или, что еще хуже, повторно связывать глобалы).
Итак, вопрос: почему вы думаетевам вообще нужен глобальный доступный для записи? Есть много способов их избежать, но «правильное» решение (я) зависит от конкретного варианта использования, о котором вы ничего не говорите.