Скрипты и модули
Contents
Скрипты и модули#
Создадим два файла.
Файл mymodule.py
.
print("Начало импортирования модуля mymodule.py")
def f():
print("Вызов функции f из модуля mymodule.py" )
print("Конец импортирования модуля mymodule.py")
Файл myscript.py
import mymodule
print(type(mymodule))
mymodule.f()
Если эти файлы лежат в одной папке, то запуск myscript.py приведет к следующему результату.
>>> python myscript.py
Начало импортирования модуля mymodule.py
Конец импортирования модуля mymodule.py
<class 'module'>
Вызов функции f из модуля mymodule.py
>>>
Разберем, что здесь происходит.
import mymodule
импортирует функциюf
из модуля с именемmymodule
. Т.к. такого модуля нет в стандартной библиотеке и среди установленных внешних библиотек, то python ищет модуль в текущей папке, находит файлmymodule.py
и импортирует его. При импортировании модуля, его файл с исходным кодом интерпретируется. Чтобы сократить время повторных импортированийbyte code
сохраняется в папке__pycache__
, что позволяет пропустить этап компиляции в байт код, если уже существует актуальная версия в кэше.По завершении импортирование управление возвращается импортирующему модулю (скрипт
myscript.py
в данном случае). Результатом импортирования является объект типаmodule
, который связывается с именемmymodule
в пространстве именmyscript.py
. Если бы строка импортирования выгляделаfrom mymodule import f
, то в пространство именmyscript.py
заводится имяf
, которое связывается с объектом по имениf
из пространства именmymodule
.Выражение
mymodule.f
говорит интерпретатору искать имяf
в пространстве имен модуляmymodule
;
Пространства имен модулей#
Более подробно пространства имён буду обсуждаться позже, а здесь обратим внимания на пространства имён модулей. Пространство имён — таблица имен и связанных с ними объектов. Таких таблицы в любой момент в программе несколько, например, таблица globals
“глобальных” переменных и таблица locals
локальных переменных, например, для функции, а также пространство builtins встроенных функций, которое доступно абсолютно везде и в любой момент времени интерпретации.
У каждого модуля своё пространство имён globals
, т.е. глобальность пространства имён распространяется только на текущий модуль (файл). Это значит, что имена созданные в импортированном модуле напрямую не доступны в импортирующем модуле, если не были явно импортированы (from mymodule import *
). Встроенная функция globals возвращает словарь переменных (ключ — имя, значение — объект) из глобального пространства имён. Чтобы продемонстрировать это изменим содержимое предыдущих файлов следующим образом.
Файл mymodule.py
.
print("Начало импортирования модуля mymodule.py")
x = 0
print(globals().keys())
print("Конец импортирования модуля mymodule.py")
Файл myscript.py
import mymodule
y = 1
print(globals().keys())
Тогда запуск файла myscript.py
привет к чему-то похожему
>>> python myscript.py
Начало импортирования модуля mymodule.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', 'x'])
Конец импортирования модуля mymodule.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'mymodule', 'y'])
>>>
Можно заметить, что глобальные пространства имён не только имёют уникальные друг для друга переменные x
и y
, но имеются и некоторые другие отличия, связанные с тем, что myscript.py
запущен непосредственно, а mymodyle.py
загружается при импортировании.
Модуль и скрипт#
Чтобы выяснить, запущен ли данный файл непосредственно или импортирован в другом файле используется выражение __name__ == "__main__"
. Такой подход основывается на том, что python автоматически создаёт имя “__name__” в глобально пространстве имен каждого модуля и скрипта в момент начала их обработки, и связывает это имя с строкой “__main__”, если файл запущен в качестве скрипта и с именем файла (за исключением расширения .py
), если файл запускается при импортировании.
Продемонстрируем это на следующих файлах
Файл mymodule.py
.
print("Начало импортирования модуля mymodule.py")
print(__name__)
if __name__ == "__main__":
print("Я был непосредственно запущен")
print("Конец импортирования модуля mymodule.py")
Файл myscript.py
import mymodule
print(__name__)
if __name__ == "__main__":
print("Я был непосредственно запущен")
Тогда запуск файла myscript.py
привет к чему-то похожему
>>> python myscript.py
Начало импортирования модуля mymodule.py
mymodule
Конец импортирования модуля mymodule.py
__main__ Я был непосредственно запущен
>>>