Если видео недоступно для просмотра, попробуйте выключить блокировщик рекламы.

Как писать скрипты, мы уже узнали. Теперь представим, что у нас есть файл с кодом, который мы запускаем как скрипт. Файл разрастается, в нём появляются функции и прочие определения. В какой-то момент мы понимаем, что хотим переиспользовать, скажем, функцию из этого модуля в другом модуле. Значит, нужно импортировать!

Импортирование скриптов

Давайте же смоделируем описанную выше ситуацию. Так будет выглядеть исходный скрипт:

# file <first_script.py>

def greet(who):
    print('Hello, {}!'.format(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!

Что мы видим — при выполнении второго скрипта выполнился и первый, хотя мы всего лишь импортировали из него одну функцию! Такова цена за простоту написания скриптов! Поскольку файл первого скрипта содержит не только определения, но и непосредственные действия (statements), то при загрузке файла (которая происходит при импорте модуля) эти действия будут выполнены. Теперь представьте, что мы бы импортировали скрипт, в котором не просто что-то печатается на экран, а удаляются какие-то файлы или того хуже — запускаются межконтинентальные ракеты!

Выходит, нам нужно как-то различать ситуации когда

  1. модуль выполняется как скрипт (выполняем побочные действия),
  2. модуль или его содержимое импортируются (не выполняем побочные действия).

Для этого нам понадобится немного магии!

Специальная переменная __name__

Машинерия импортирования при загрузке модуля в первый раз (первый для текущего запуска интерпретатора) добавляет в этот модуль несколько переменных специального вида. Этих переменных довольно много, но нам пока интересна одна — переменная __name__.

Не стоит пугаться такого странного имени аж с четыремя символами подчёркивания: такие имена часто встречаются в Python-коде и как правило имеют какой-то специальный смысл. Опытный питонист помнит наизусть пару десятков таких переменных, а ещё про эти переменные любят спрашивать на собеседованиях.

Что же хранит переменная __name__ в каждом конкретном случае? В этом и весь секрет!

  • Если происходит обычный импорт, то эта переменная содержит полное имя модуля (полностью квалифицированное).
  • Если же происходит запуск в качестве скрипта, то переменная получает специальное значение — строку '__main__'.

Глядя на значение этой переменной, можем отличать "запуск" от импортирования.

Слово "main" используется во многих языках для именования функции, которая вызывается автоматически при старте программы, потому и в Python это слово используется в похожем смысле

Давайте вернёмся к нашему примеру и перепишем first_script.py с применением этого нового знания:

# file <first_script.py>

def greet(who):
    print('Hello, {}!'.format(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('Hello, {}!'.format(who))

def main():
    greet('Bob')
    greet('Ann')

if __name__ == '__main__':
    main()

Такой скрипт можно

  • запускать непосредственно;
  • запускать из других скриптов, вызывая функцию main;
  • использовать как библиотеку.

Запускаемые пакеты

Рассмотрим немного экзотический, но всё же встречающийся случай — запуск пакета. Могло бы показаться, что раз при загрузке пакета всегда загружается модуль __init__.py, то и функцию main, и условие нужно располагать в нём. Но авторы по ряду причин решили реализовать запуск пакетов несколько иначе: при загрузке пакета пред запуском ищется модуль __main__.py и выполняется, как скрипт. Здесь мы не будем углубляться в причины, побудившие авторов языка сделать именно так, и просто запомним, что исполняемые пакеты всегда содержат скрипт __main__.py.

Когда же может понадобится запуск пакета? Сходу можно представить такой пример. Пусть мы имели один небольшой скрипт. Со временем кода в нём становилось всё больше — настолько много, что этот скрипт стало совершенно невозможно поддерживать. Мы решили превратить один модуль в пакет, содержащий несколько. Но как такой пакет в дальнейшем запускать? Вот для этого мы и можем использовать модуль __main__.py!

Ссылки


Дополнительные материалы

  1. shebang (Unix)
Мы учим программированию с нуля до стажировки и работы. Попробуйте наш бесплатный курс «Введение в программирование» или полные программы обучения по Node, PHP, Python и Java.

Хекслет

Подробнее о том, почему наше обучение работает →