Поведение import и from-import в Python

Поведение import и from-import в Python

@python_quiz

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

Код из квиза:

python

Коротко — программа выведет:

text

Дальше объясню, почему так происходит, разберу все варианты ответов и покажу тонкости import-механизма.

По шагам: что делает каждый оператор

  1. import math as m

- Загружает встроенный модуль math и создаёт локальную привязку m к модулю. Также соответствующий объект модуля оказывается в sys.modules['math'].

  1. m_used = m.pi

- Берёт значение константы pi из модуля m и сохраняет в m_used. Это просто использование ранее импортированного модуля.

  1. math = 42

- Создаёт (или переопределяет) переменную math в текущей области видимости и связывает её с числом 42. Это затеняет имя math в глобальном/локальном пространстве имён, но не трогает sys.modules.

  1. from math import sqrt

- Оператор from <module_name> import <name> использует механизм импорта по имени модуля (через import machinery и sys.modules), а не текущую переменную с именем math. То есть модуль ищется и загружается по строковому имени 'math', а затем из него извлекается sqrt. Полученная функция связывается в текущем пространстве имён как sqrt.

  1. print(math, sqrt(4))

- Выводит значение переменной math (которое равно 42) и результат вызова sqrt(4) (равный 2.0).

Ключевой момент: присвоение имени math = 42 не мешает импорту from math import ..., потому что импорт идёт по имени модуля, а не по текущему значению переменной math.

Разбор вариантов ответов

  • "Выведет: 42 2.0"

Обоснование: как показано выше, имя math было перезаписано числом, а sqrt импортирована из модуля math (через import machinery). Именно это и распечатается.

  • "Выведет: 3.141592653589793 2.0"

Неверно, потому что к моменту печати имя math уже связано с 42. Если бы не было присвоения math = 42, тогда math действительно ссылался бы на модуль и math.pi дал бы pi. Но в данном коде мы явно переназначили math.

  • "ImportError: cannot import name 'sqrt'"

Неверно в обычных условиях, потому что модуль math входит в стандартную библиотеку и содержит sqrt. Оператор from math import sqrt успешно найдёт и импортирует sqrt. Единственная ситуация, когда такое исключение могло бы возникнуть — если модуль math был бы удалён из sys.modules и поиск не нашёл бы подходящего модуля (или обычное окружение модифицировано нетипичным образом).

  • "NameError: name 'math' is not defined"

Неверно: имя math действительно определено — мы присвоили ему значение 42. NameError возник бы только если бы перед печатью имя math не было бы ни импортировано, ни присвоено.

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

  • Оператор from <module> import name работает с модулем по его строковому имени. Даже если в текущей области видимости есть переменная с таким именем, это не влияет на то, откуда берутся объекты для импорта.
  • Пример, иллюстрирующий ту же идею:
python

Выведет:

text
  • Если же вы вручную удалите запись о модуле из sys.modules и помешаете загрузке (и не будет доступных загрузчиков), тогда from math import sqrt может попытаться заново загрузить модуль или выдать ошибку. В нормальном коде такие манипуляции редки и не типичны.

Вывод

Имя переменной в текущей области видимости и механизм импорта — разные вещи. Переменная math = 42 не мешает from math import sqrt, потому что импорт обращается к модулю по имени в системе модулей Python, а затем привязывает нужные символы в текущем пространстве имён. Поэтому код печатает число, присвоенное переменной, и результат работы импортированной функции.

Report Page