Подтверждение разницы между import * и from xxx import *

Я был удивлен, узнав, что

import foo

и

from foo import *

имели разные последствия для глобальных участников. Я хотел подтвердить, что мои эксперименты - правильное поведение.

В первом примере изменение члена в модуле foo будет отражать весь код, который импортирует foo. Однако изменение этого элемента в более позднем случае, по-видимому, влияет на файл, в который он был импортирован. Другими словами, использование более позднего подхода даст каждому импортирующему файлу собственную копию членов из foo.

поведение, которое я хочу, - иметь доступ к foo.x из всех файлов, иметь возможность изменять его из всех файлов и отражать это изменение во всех файлах (если это действительно так).

Ответ 1

Да, ваши наблюдения верны. Это является следствием того, как связывание работает в Python.

Когда вы делаете

import foo

тогда foo становится глобальным именем, которое ссылается на модуль foo. Когда вы делаете

foo.bar = 7

Затем выполняется ссылка и загружается объект foo. Затем 7 сохраняется в атрибуте bar.

Когда другой модуль импортирует foo, он просто вытаскивает объект из sys.modules['foo'] и получает измененное значение.

Когда вы делаете

from foo import bar

globals()['bar'] устанавливается в качестве ссылки foo.bar. Когда один из них делает

 bar = 7

globals()['bar'] больше не ссылается на foo.bar, а ссылается на копию 7. То есть первоначальная привязка в глобальной области модуля импорта просто заменяется.

В первом примере один из них модифицирует атрибуты объекта, который хранится в sys.modules, и будет общим для всех модулей, которые его импортировали. Во втором примере изменяется глобальная область модуля импорта.

Если бы кто-то делал что-то по строкам

 from foo import fobaz
 fobaz.foobar = 7

Затем это изменение будет распространено на другие модули импорта, потому что одно не переписывает глобальную ссылку, а следует за ней, чтобы изменить атрибут объекта, на который он указывает. По существу, вы должны иметь возможность изменять изменяемые объекты, пока вы не перезаписываете глобальную привязку.

Я думаю, что что-то вроде этого самое близкое, что вы сможете полностью перейти к истинному глобальному в python. В качестве языка он значительно присваивает пространствам имен.

Ответ 2

Учитывая, что глобальные переменные обычно считаются плохими, я подозреваю, что "истинная глобальная" переменная была бы очень плохой.

Другим способом получения аналогичного поведения является использование атрибутов class-scope в одноэлементном объекте и просто импорт. Тогда становится понятнее, откуда вы получаете глобальную переменную.