Почему после импортирования только одной функции модуля она видит другие объекты этого же модуля?

Рейтинг: 1Ответов: 2Опубликовано: 13.02.2025

Допустим, в модуле my_library есть функция a, которая использует функцию b, объявленную в этом же модуле:

# my_library.py

def a():
    print("I'm function A and I'm running B inside me")
    b()

def b():
    print("I'm function B")

Я импортирую из модуля только функцию a:

from my_library import a

Почему a видит функцию b, которую я не импортирую и которая не определена внутри самой функции a?

Ответы

▲ 0

Когда вы импортируете только функцию a, функция b никуда не девается. Создается новая область видимости со всеми переменными модуля, и одна функция этого модуля видит все другие переменные данного модуля.

▲ 0

При импортировании, модуль выполняется как программа от первой до последней строки. При этом создается объект типа ModuleType, который сохраняется по исходному имени в кеше sys.modules. При любом повторном импортировании модуль уже не выполняется при загрузке, а извлекается в готовом виде из кеша. Объекты, которые в коде модуля рассматриваются как глобальные, хранятся в его свойстве __dict__. Функции модуля, которые обращаются к глобальным переменным, ищут их именно там. А чтобы сохранить мобильность функции как самостоятельного объекта, связь с пространством имен модуля поддерживается через свойство функции __globals__. Это свойство указывает на ранее упомянутый словарь __dict__ исходного модуля.

Что происходит в примере из вопроса? Импортируя функцию строкой from my_library import a, вы загружаете весь модуль. При этом функция будет доступна из вашей программы по имени a, модуль сохранится как sys.modules['my_library'], а пространство глобальных имен функции будет хранится в словаре, который будет доступен по трем именам:

sys.modules['my_library'].__dict__
sys.modules['my_library'].__dict__['a'].__globals__   # он же a.__globals__
sys.modules['my_library'].__dict__['b'].__globals__

Функция a во время работы будет искать функцию b в словаре a.__globals__, а не в текущем пространстве глобальных имен. Если в пределах модуля функция b не определена, то при попытке выполнить a() возникнет ошибка NameError: name 'b' is not defined. Вы можете определить b за пределами модуля, но a не сможет её увидеть, пока в словаре a.__globals__ не появится ключ "b", указывающий на вашу функцию.


P.S. Хорошее, несмотря на возраст, видео на тему импорта и работы с модулями: David Beazley - Modules and Packages: Live and Let Die! - PyCon 2015