Модули будут, вероятно, более понятны, если представлять их, как простые пакеты имен, – то есть место, где определяются переменные, которые должны быть доступны остальной системе.
С технической точки зрения каждому модулю соответствует отдельный файл, и интерпретатор создает объект модуля, содержащий все имена, которым присвоены какие-либо значения в файле модуля. Проще говоря, модули – это всего лишь пространства имен (места, где создаются имена), и имена, находящиеся в модуле, называются его атрибутами.В данной тематике мы разберем как работает этот механизм.
С технической точки зрения каждому модулю соответствует отдельный файл, и интерпретатор создает объект модуля, содержащий все имена, которым присвоены какие-либо значения в файле модуля. Проще говоря, модули – это всего лишь пространства имен (места, где создаются имена), и имена, находящиеся в модуле, называются его атрибутами.В данной тематике мы разберем как работает этот механизм.
Файлы создают пространства имен
Итак, как же файлы трансформируются в пространства имен? Суть в том, что каждое имя, которому присваивается некоторое значение на верхнем уровне файла модуля (то есть не вложенное в функции или в классы), превращается в атрибут этого модуля.
Например, операция присваивания, такая как X = 1, на верхнем уровне модуля M.py превращает имя X в атрибут модуля M, обратиться к которому из-за пределов модуля можно как M.X. Кроме того, имя X становится глобальной переменной для программного кода внутри M.py, но нам необходимо более формально объяснить понятия загрузки модуля и областей видимости, чтобы понять, почему:
• Инструкции модуля выполняются во время первой попытки импорта. Когда модуль импортируется в первый раз, интерпретатор Python создает пустой объект модуля и выполняет инструкции в модуле одну за другой, от начала файла до конца.
• Операции присваивания, выполняемые на верхнем уровне, создают атрибуты модуля. Во время импортирования инструкции присваивания, выполняемые на верхнем уровне файла и не вложенные в инструкции def или class (например, =, def), создают атрибуты объекта модуля – при присваивании имена сохраняются в пространстве имен модуля.
• Доступ к пространствам имен модулей можно получить через атрибут __dict__ или dir(M). Пространства имен модулей, создаваемые операцией импортирования, представляют собой словари – доступ к ним можно получить через встроенный атрибут __dict__, ассоциированный с модулем, и с помощью функции dir. Функция dir – это примерный эквивалент отсортированного списка ключей атрибута __dict__, но она включает унаследованные имена классов, может возвращать не полный список и часто изменяется от версии к версии.
• Модуль – это единая область видимости (локальная является глобальной). Как мы видели в главе 17, имена на верхнем уровне модуля подчиняются тем же правилам обращения/присваивания, что и имена в функциях, только в этом случае локальная область видимости совпадает с глобальной (точнее, они следуют тому же правилу LEGB поиска в областях видимости, с которым мы познакомились в главе 17, только без уровней поиска L и E).
Но в модулях область видимости модуля после загрузки модуля превращается в атрибут-словарь объекта модуля. В отличие от функций (где локальное пространство имен существует только во время выполнения функции), область видимости файла модуля превращается в область видимости атрибутов объекта модуля и никуда не исчезает после выполнения операции импортирования.
Ниже эти понятия демонстрируются в программном коде. Предположим, мы
создаем в текстовом редакторе следующий файл модуля с именем module2.py:
Print(‘starting to load...’)
import sys
name = 42
def func(): pass
class klass: pass
print(‘done loading.’)
Когда модуль будет импортироваться в первый раз (или будет запущен как программа), интерпретатор выполнит инструкции модуля от начала до конца. В ходе операции импортирования одни инструкции создают имена в пространстве имен модуля, а другие выполняют определенную работу. Например, две инструкции print в этом файле выполняются во время импортирования:
>>> import module2
starting to load...
done loading.
Но как только модуль будет загружен, его область видимости превратится в пространство имен атрибутов объекта модуля, который возвращает инструкция import. После этого можно обращаться к атрибутам в этом пространстве
имен, дополняя их именем вмещающего модуля:
>>> module2.sys
<module ‘sys’ (built-in)>
>>> module2.name
42
>>> module2.func
<function func at 0x026D3BB8>>
>>> module2.klass
<class module2.klass>
Здесь именам sys, name, func и klass были присвоены значения во время выполнения инструкций модуля, поэтому они стали атрибутами после завершения операции импортирования. О классах мы будем говорить в шестой части книги, но обратите внимание на атрибут sys – инструкции import действительно присваивают объекты модулей именам, а любая операция присваивания на
верхнем уровне файла создает атрибут модуля.
Внутри интерпретатора пространства имен хранятся в виде объектов словарей. Это самые обычные объекты словарей с обычными методами. Обратиться к словарю пространства имен модуля можно через атрибут __dict__ модуля (не забудьте обернуть вызов этого метода вызовом функции list – в Python 3.0 он возвращает объект представления!):
>>> list(module2.__dict__.keys())
[‘name’, ‘__builtins__’, ‘__file__’, ‘__package__’, ‘sys’, ‘klass’, ‘func’,
‘__name__’, ‘__doc__’]
Имена, которые были определены в файле модуля, становятся ключами внутри словаря, таким образом, большинство имен здесь отражают операции
присваивания на верхнем уровне в файле. Однако интерпретатор Python добавляет в пространство имен модуля еще несколько имен, например __file__ содержит имя файла, из которого был загружен модуль, а __name__ – это имя, под которым модуль известен импортерам (без расширения .py и без пути к каталогу).
Комментариев нет:
Отправить комментарий