Поведение import vs from ... import в Python

Поведение import vs from ... import в Python

@python_quiz

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

Кратко: рассматриваем фрагмент, где сначала импортируется модуль, затем меняется его атрибут, а затем выполняется from ... import. Посмотрим, что напечатает и почему.

Условие (исходный код)

python

Для наглядности предполагаем, что внутри pkg/utils.py изначально было что-то вроде:

python

(Это обычное предположение, объясняющее, откуда взялась альтернатива "10" в вариантах ответа.)

Что выводится и почему (кратко)

В данном порядке операций в консоль будет выведено число 20. Пояснение: первый импорт получает модуль pkg.utils как объект; затем присваиванием utils.VALUE = 20 мы меняем атрибут модуля. Когда выполняется from pkg.utils import VALUE, Python читаёт текущее значение атрибута в модуле и связывает локальное имя VALUE с этим значением (в момент импорта). Поскольку в модуле сейчас 20, импортированное имя получает значение 20.

Пошаговая расшифровка

  1. from pkg import utils — загружается пакет pkg, его атрибут utils (модуль) становится доступен под именем utils. Это эквивалентно import pkg.utils as utils в плане получения объекта модуля.
  2. utils.VALUE = 20 — изменение атрибута VALUE в объекте модуля utils. Теперь внутри pkg.utils имя VALUE указывает на целое 20.
  3. from pkg.utils import VALUE — при этом выполняется отдельное связывание имени VALUE в текущей области видимости: Python берет текущее значение pkg.utils.VALUE (то есть 20) и присваивает его локальному имени VALUE.
  4. print(VALUE) — печатает локальное VALUE, равное 20.

Важно: from ... import копирует (связывает) объект в текущем момент, а не создаёт "живую ссылку" на атрибут модуля, если затем модуль переопределяет имя (в случае неизменяемых объектов эффект как копирование значения).

Анализ вариантов ответов

  • 10 — такое получилось бы, если бы сначала выполнили from pkg.utils import VALUE, а затем уже изменили utils.VALUE = 20. В текущем порядке изменение происходит до from ... import, поэтому этот вариант не соответствует.
  • 20 — соответствует описанному порядку операций: изменение атрибута модуля происходит до from ... import, поэтому импортирует уже обновлённое значение.
  • ImportError — не произойдет, если пакет и модуль существуют и корректно импортируются. В данном фрагменте явных причин для ImportError нет.
  • None — не появится, так как VALUE явно присвоено числовое значение; печатать будет не None.

Демонстрация: что меняет порядок

Ниже пара примеров, иллюстрирующих разницу порядка и поведение при мутабельных объектах.

1) Если сначала импортируем значение, затем меняем атрибут модуля:

python

2) Порядок как в квизе (сначала модуль, потом изменение, потом from-import):

python

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

python

Вывод: при работе с изменяемыми объектами важно различать мутацию (внутри объекта) и переназначение имени в модуле.

Выводы и рекомендации

  • Оператор from module import name связывает имя в момент выполнения инструкции, беря текущее значение из модуля.
  • Изменение атрибута модуля до from ... import повлияет на импортируемое значение; изменение после — нет (если это переназначение имени).
  • Для избежания путаницы и неожиданных рассинхронизированных значений предпочтительнее использовать полные импортные формы (import module) и обращаться через module.name, особенно если значение может меняться.
  • При работе с изменяемыми объектами помните: from ... import obj даёт ссылку на тот же объект, поэтому его внутренняя мутация будет видна в обоих местах; но переназначение имени в модуле не обновит локальное имя.

Report Page