Сравнение: чем отличается изменение атрибута уже импортированного модуля от переназначения имени, импортированного через конструкцию from module import name?
При обычном импорте модуля имя указывает на объект модуля, поэтому обращение к его атрибуту получает актуальное значение атрибута. При импорте отдельного имени Python создаёт в текущем пространстве имён отдельную привязку к объекту; последующее переназначение имени в модуле эту привязку не обновляет.
Модель модулей Python построена вокруг пространств имён: модуль служит отдельным контейнером для имён, а импорт предоставляет к ним доступ из другого пространства. Такой подход решает проблему изоляции реализаций и позволяет повторно использовать код без копирования его в каждый файл.
Форма from module import name появилась как удобный способ обращаться к выбранному имени без постоянного указания имени модуля. Удобство достигается ценой менее очевидной связи между локальным именем и исходным модулем.
Если один модуль изменил значение своего атрибута, другой модуль может продолжить видеть старое значение, когда использовал импорт отдельного имени. Ошибка особенно опасна для настроек, зарегистрированных обработчиков и заменяемых зависимостей: разработчик ожидает динамическое обновление, но фактически работает с прежней привязкой.
Нужно различать изменение объекта и переназначение имени. Изменение общего изменяемого объекта обычно видно через обе ссылки, а переназначение имени создаёт новую связь только в конкретном пространстве имён.
При import module локальное имя ссылается на объект модуля. Выражение обращения к атрибуту фактически ищет атрибут в этом объекте в момент обращения, поэтому переназначенный атрибут будет прочитан заново.
При from module import name значение атрибута извлекается во время импорта и привязывается к имени в текущем пространстве имён. Если позднее в модуле выполнить переназначение этого атрибута, локальное имя не переключится автоматически.
В примере settings указывает на модуль, а value — на объект, который был найден при импорте. Если вместо переназначения изменить содержимое общего изменяемого объекта, обе ссылки могут увидеть это изменение, поскольку продолжают указывать на один объект.
Практическое правило: для конфигурации и зависимостей, которые могут заменяться во время работы программы, обычно безопаснее импортировать модуль и обращаться к его атрибуту. from module import name уместен, когда нужна удобная ссылка на стабильное имя и его независимость от последующих переназначений в модуле.
Импорт отдельного имени также может затруднить анализ зависимостей и тестирование: источник значения менее заметен, а подмена атрибута модуля после импорта не изменит уже созданную локальную привязку.
В приложении обработчик выбирался из модуля конфигурации. Один компонент импортировал сам модуль, другой — конкретный обработчик через from ... import .... Во время теста конфигурация заменяла обработчик, но второй компонент продолжал вызывать старый вариант.
Рассматривались два решения. Можно было оставить импорт отдельного имени и явно обновлять локальную привязку; это минимально меняет код, но создаёт дополнительный протокол синхронизации и риск новых ошибок. Другой вариант — импортировать модуль и обращаться к атрибуту через него; это чуть более многословно, зато сохраняет единую точку поиска актуальной зависимости.
Выбрали второй вариант: он сделал замену конфигурации предсказуемой и упростил тесты. Цена решения — более явные квалифицированные обращения к именам, что в данном случае повысило читаемость.
from module import name?Да, если объект не заменяется, а изменяется на месте. Обе привязки по-прежнему указывают на один объект; невидимым остаётся только последующее переназначение имени в модуле на другой объект.
Изменится только привязка в текущем пространстве имён. Атрибут исходного модуля от этого не изменится, потому что импорт отдельного имени не создаёт двустороннюю связь между двумя именами.
from module import name обновить локальное значение?Да, повторный импорт снова получит текущее значение атрибута и переназначит локальное имя. Однако это ручная синхронизация, а не автоматическое обновление; кроме того, повторное выполнение импорта не следует использовать как замену ясной архитектуре зависимостей.