Представим, что у нас есть файл с кодом, который мы запускаем как скрипт. Файл разрастается, в нем появляются функции и прочие определения. В какой-то момент мы понимаем, что хотим переиспользовать функцию из этого модуля в другом модуле. Значит, нужно импортировать. В этом уроке мы разберемся, как работает импорт скриптов.
Импортирование скриптов
Смоделируем описанную выше ситуацию. Так будет выглядеть исходный скрипт:
# file <first_script.py>
def greet(who):
print(f'Hello, {who}!')
greet('Bob')
greet('Ann')
Теперь посмотрим на новый скрипт, в котором мы хотим переиспользовать функцию greet
из первого скрипта:
# file <second_script.py>
from first_script import greet
greet('Thomas')
Запустим первый скрипт, а затем — второй. Оба файла расположены в текущей директории:
python3 first_script.py
Hello, Bob!
Hello, Ann!
python3 second_script.py
Hello, Bob!
Hello, Ann!
Hello, Thomas!
При выполнении второго скрипта выполнился и первый, хотя мы всего лишь импортировали из него одну функцию — такова цена за простоту написания скриптов.
Файл первого скрипта содержит определения и непосредственные действия, поэтому при загрузке файла при импорте модуля эти действия будут выполнены.
Теперь представьте, что мы бы импортировали скрипт, в котором не просто что-то печатается на экран, а удаляются какие-то файлы.
Выходит, нам нужно как-то различать ситуации двух типов:
- Модуль работает как скрипт — выполняем побочные действия
- Модуль или его содержимое импортируются — не выполняем побочные действия
Специальная переменная __name__
Рассмотрим механизм импорта при загрузке модуля в первый раз — а именно первый для текущего запуска интерпретатора.
Во время первой загрузки интерпретатор добавляет в модуль несколько переменных специального вида. Этих переменных довольно много, но нам пока интересна одна — переменная __name__
.
Кажется, что у переменной необычное имя — в нем целых четыре символа подчеркивания. На самом деле такие имена часто встречаются в Python-коде и как правило имеют какой-то специальный смысл. Опытный разработчик обычно помнит наизусть пару десятков таких переменных, поэтому про эти переменные любят спрашивать на собеседованиях.
Посмотрим, что хранит переменная __name__
в каждом конкретном случае:
- Если происходит обычный импорт, то эта переменная содержит полное имя модуля
- Если происходит запуск в качестве скрипта, то переменная получает специальное значение — строку
'__main__'
Глядя на значение этой переменной, мы можем отличать запуск в качестве скрипта от импортирования.
Слово main используется во многих языках для именования функции, которая вызывается автоматически при старте программы. Потому и в Python это слово используется в похожем смысле.
Давайте вернемся к нашему примеру и перепишем first_script.py
с применением этого нового знания:
# file <first_script.py>
def greet(who):
print(f'Hello, {who}!')
if __name__ == '__main__':
greet('Bob')
greet('Ann')
Теперь наш скрипт не будет приветствовать Боба и Энн, если мы будем импортировать модуль.
Функция main
Наш скрипт first_script.py
уже достаточно хорош, но можно немного его улучшить.
В теле условия if __name__…
перечислен набор действий, которые выполняются при запуске скрипта. Со временем таких действий может стать достаточно много.
Нередко происходят ситуации, когда нужно переиспользовать этот кусок кода. Поэтому существует соглашение: в теле условия if __name__…
делают всего один вызов функции main
без аргументов. Эту функцию объявляют выше в этом же модуле. При этом само условие принято располагать в самом конце модуля скрипта.
С учетом всех описанных рекомендаций финальная версия скрипта first_script.py
будет выглядеть так:
#!/usr/bin/env python3
def greet(who):
print(f'Hello, {who}!')
def main():
greet('Bob')
greet('Ann')
if __name__ == '__main__':
main()
Такой скрипт можно:
- Запускать непосредственно
- Запускать из других скриптов, вызывая функцию
main
- Использовать как библиотеку
Запускаемые пакеты
Рассмотрим немного необычный, но все же встречающийся случай — запуск пакета.
Может показаться, что раз при загрузке пакета всегда загружается модуль __init__.py
, то функцию main
и условие нужно располагать в нем.
Но запуск пакетов реализован несколько иначе: при загрузке пакета интерпретатор ищет __main__.py
и выполняет его как скрипт. Здесь мы не будем углубляться в причины — просто запомним, что исполняемые пакеты всегда содержат скрипт __main__.py
.
Когда может понадобиться запуск пакета? Возьмем для примера один небольшой скрипт. Со временем кода в нем становилось все больше — настолько много, что этот скрипт стало совершенно невозможно поддерживать.
Представим, что мы решили превратить один модуль в пакет, содержащий модули. Но как такой пакет в дальнейшем запускать? Как раз в этом нам поможет модуль __main__.py
.
Самостоятельная работа
Создайте модуль
module.py
следующего вида:print(f"__name__ == '{__name__}'")
В REPL импортируйте модуль. Запускайте интерпретатор, находясь в директории с модулем. В приглашении выполните
import module
Посмотрите, что выведется на экран
Запустите модуль на исполнение. Для этого вызовите
python3 module.py
из директории, в которой вы создали модульПосмотрите, что выводится на экран на этот раз
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.