Как Python связывает имена при import и from import

Как Python связывает имена при import и from import

@python_quiz

Разберем этот квиз

Коротко: в представленном фрагменте на экран будет выведено 20. Ниже — почему так происходит, разбор вариантов и примеры, которые проясняют поведение импорта в разных сценариях.

Условие (код из квиза)

python

Предполагается, что внутри модуля pkg.utils изначально было какое-то значение VALUE (например, 10). Важно последовательность операций: сначала импорт модуля под именем utils, затем присвоение utils.VALUE = 20, затем из модуля импортируется имя VALUE в локальную область видимости.

Короткое объяснение поведения

  • Операция import pkg.utils as utils загружает модуль и создаёт локальную переменную utils, указывающую на объект модуля.
  • Присвоение utils.VALUE = 20 изменяет атрибут VALUE у объекта модуля.
  • Оператор from pkg.utils import VALUE связывает локальное имя VALUE с тем объектом, на который в данный момент указывает атрибут VALUE в модуле.
  • Поэтому локальное VALUE получит значение 20, и print(VALUE) выведет 20.

Главная идея: from ... import привязывает локальное имя к текущему объекту из модуля в момент выполнения импорта.

Разбор вариантов (логика)

  • Будет выведено 10 — такое произошло бы, если бы из модуля VALUE был импортирован до того, как utils.VALUE сменили на 20. Здесь же присвоение происходит ДО from import.
  • Будет выведено 20 — соответствует ситуации с присвоением до from import (как в коде).
  • Будет выведено None — потребовалось бы, чтобы VALUE действительно было None в модуле на момент from import; это не следует из кода.
  • Возникнет ошибка импорта — возникнет только если модуль pkg.utils вообще не найден/не загружается. В рамках примера модуль предполагается доступным.

Демонстрация: воспроизвести поведение в одном файле

Чтобы не создавать файловой структуры пакета, можно временно подставить модуль в sys.modules:

python

Этот пример показывает, что присвоение атрибута модуля до from import влияет на значение локальной переменной VALUE.

Важное уточнение: mutable vs immutable

Поведение зависит не только от времени привязки, но и от того, изменяется ли объект путём присваивания или мутации.

Пример с изменяемым объектом (список):

python

Выводы:

  • Если объект мутируется (методы, изменение содержимого), обе ссылки (в модуле и локальная) указывают на один и тот же объект и изменения видны.
  • Если же атрибут модуля переназначается (utils.VALUE = новый_объект), локальная переменная, импортированная ранее через from, не поменяет свою привязку — она всё ещё указывает на старый объект.

Дополнительные замечания

  • from ... import фактически выполняет привязку имени в текущую область видимости — не «волшебную связь» с модулем, а обычное присваивание имени.
  • import pkg.utils as utils и from pkg.utils import VALUE дают разные способы доступа: первый даёт доступ к самому модулю и его атрибутам динамически, второй — локальную копию ссылки на объект.
  • Если модуль действительно отсутствует, то оба импорта вызовут ImportError / ModuleNotFoundError.

Итог

Поведение в примере определяется порядком операций и семантикой from ... import: локальное имя привязывается к тому объекту, который в модуле доступен на момент импорта. Для неизменяемых объектов (int, str и т.д.) переназначение атрибута модуля после from не повлияет на локальную переменную; для изменяемых объектов видны мутации, но не переназначения.

Report Page