Почему после импортирования только одной функции модуля она видит другие объекты этого же модуля?
Допустим, в модуле 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?
Ответы (2 шт):
Когда вы импортируете только функцию a, функция b никуда не девается. Создается новая область видимости со всеми переменными модуля, и одна функция этого модуля видит все другие переменные данного модуля.
При импортировании, модуль выполняется как программа от первой до последней строки. При этом создается объект типа 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