Зачем нужен __main__ в Python
hard

Зачем нужен __main__ в Python

Настраиваем автозапуск кода

Часто при разборе чужого кода можно встретить файл __main__.py или внутри самого скрипта увидеть конструкцию типа «if __name__ == __main__». Сегодня разберёмся, что это за __main__ и зачем он нужен. 

Как запускается скрипт на Python

Самый простой способ запустить код на Python — установить интерпретатор, а затем в командной строке написать python3 и указать имя файла со скриптом. Например, если у нас скрипт сохранён в файле script.py, то для запуска кода в терминале пишем такое:

python3 script.py

После этого компьютер возьмёт наш файл и попросит Python его выполнить. Так как Python — это интерпретируемый язык программирования, то код будет выполняться построчно, шаг за шагом. 

Давайте это проверим и создадим простой скрипт, который сохраним в файле script.py:

def greet_user(user_name): 
	print(f'Привет, {user_name}!') 

name = 'Паша'
greet_user(name)
Как запускается скрипт на Python

Теперь копнём глубже и посмотрим, как именно компьютер начинает выполнять наш код. В каждом скрипте есть верхний уровень среды исполнения — то место, откуда интерпретатор начинает исполнение команд. 

В нашем случае компьютер начинает с самой первой строчки и по очереди обрабатывает все остальные, сверху вниз: функция → тело функции → переменная → запуск функции. Чтобы в этом убедиться, поменяем местами последнюю пару строк кода и посмотрим, что получится:

def greet_user(user_name): 
	print(f'Привет, {user_name}!') 

greet_user(name)
name = 'Паша'
Как запускается скрипт на Python

Мы сразу получили ошибку: Python встретил переменную раньше, чем мы её объявили, и не знает, что с ней делать. А всё потому, что мы поменяли порядок строк, чтобы убедиться, что он важен и что компьютер обрабатывает и сразу выполняет команды в том порядке, как они написаны.

Посложнее: запуск во время импорта

В разных проектах мало кто обходится только одним скриптом: чаще всего разработчики подключают дополнительные библиотеки и внешние файлы для расширения возможностей программы. Чтобы подключить внешний файл, используют команду import:

import <имя_файла>

Так можно подключить любой внешний скрипт, который уже умеет делать то, что нам нужно в новом проекте. Например, мы можем использовать наш файл script.py как внешний файл для импорта и подключить его в новой программе:

import script.py

Создадим новый файл new_script.py, в котором подключим первый скрипт, и посмотрим, что произойдёт при запуске:

import script

def wish_luck(user_name): 
	print(f'Желаю удачи, {user_name}') 

script.greet_user('Катя')
wish_luck('Катя')
Зачем нужен __main__ в Python

Странно, но у нас внезапно появилось приветствие Паши, хотя в основном скрипте этого нет. Давайте разберёмся, что тут происходит:

  1. Мы импортируем скрипт script.py.
  2. Компьютер в этой папке и в среде окружения ищет этот файл, находит и начинает построчно его выполнять. Так происходит для того, чтобы при вызове функции из импортированного файла она была уже загружена и компьютер знал, что с ней делать.
  3. В импортированном файле на третьей строке идёт объявление переменной, а на следующей — вывод приветствия на экран.
  4. Так как всё выполняется построчно, это приветствие сработает при импорте, и мы поприветствуем Пашу даже до запуска основного кода в new_script.py.

Получается, что при импорте Python переходит к новому файлу и начинает тоже выполнять его шаг за шагом. Тогда как нам подключить первый скрипт, чтобы оттуда взять только функцию приветствия, но без исполнения остального кода? И вот здесь нам понадобится __main__.

Что такое __main__

Каждый скрипт в Python выполняется на каком-то уровне. При запуске напрямую из командной строки скрипт выполняется на верхнем уровне: мы запустили его напрямую, а не из другого скрипта. Верхний уровень исполнения называется __main__, и это значение хранится в скрытой переменной __name__. Её можно посмотреть командой:

print(__name__)

Добавим эту команду в первый скрипт в самое начало и посмотрим на её значение:

print(__name__)

def greet_user(user_name): 
	print(f'Привет, {user_name}!') 

name = 'Паша'
greet_user(name)
Что такое __main__

Получается, при прямом запуске код запускается на самом верхнем уровне, а само значение уровня хранится в переменной __name__. Теперь запустим второй файл, где мы импортируем наш скрипт, и посмотрим, какое будет значение этой переменной при импорте, а не при запуске напрямую:

Что такое __main__

Смотрите, что здесь произошло:

  1. Компьютер начал работать с файлом new_script.py.
  2. Первой строчкой он встретил команду импорта и пошёл работать с файлом script.py.
  3. В этом файле первая команда — вывод значения уровня запуска скрипта.
  4. Компьютер знает, что он запускает второй скрипт не напрямую, а из файла new_script.py, поэтому значение __name__ становится уже не __main__, а script.
  5. При этом всё остальное выполняется точно так же, как и раньше, включая приветствие Паши.

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

Что делает if __name__ == '__main__' 

Проверить, на каком уровне работает текущий код, можно командой:

if __name__ == '__main__'

Она смотрит, совпадает ли уровень выполнения с верхним, и в зависимости от ответа можно настроить выполнение разных фрагментов кода. 

Сделаем так, чтобы в первом скрипте мы приветствовали Пашу только при верхнеуровневом запуске, из командной строки. Для этого добавим проверку уровня перед выводом приветствия:

print(__name__)

def greet_user(user_name): 
	print(f'Привет, {user_name}!') 

if __name__ == '__main__':
	name = 'Паша'
	greet_user(name)
Что делает if __name__ == '__main__' 

Пока всё выглядит так же, как и раньше, не считая вывода уровня исполнения. А теперь запустим второй файл, где мы импортировали script.py, и посмотрим, что изменилось:

Что делает if __name__ == '__main__' 

Часто конструкция if __name__ == '__main__' используется для автозапуска основного кода в главном скрипте — компьютер доходит до этой строчки, проверяет уровень запуска и выполняет всё, что идёт внутри. Это позволяет обойтись без главной функции, которую мы обычно вызываем в конце для запуска кода. А ещё это убережёт от автозапуска ненужного кода при импорте этого файла в другой проект.

Какие ещё есть способы запуска кода

Есть ещё один способ запустить код — использовать модуль runpy. Способ пригодится, когда мы хотим что-то запустить внутри основного скрипта, но при этом ничего не импортировать. Добавим нужный код в скрипт new_script.py:

import runpy
import script

def wish_luck(user_name): 
	print(f'Желаю удачи, {user_name}') 

script.greet_user('Катя')
wish_luck('Катя')

runpy.run_path('script.py', run_name='__main__')
Какие ещё есть способы запуска кода

Обратите внимание, как менялся уровень запуска script.py:

  1. При импорте он был равен script.
  2. Потом выполнилось основное содержимое файла new_script.py.
  3. Затем мы сказали запустить файл script.py и указали для него уровень выполнения __main__.
  4. Первый скрипт увидел, что у него высший уровень выполнения, и вывел значение __main__, а потом поприветствовал Пашу, потому что сработало условие уровня.

Что дальше

В следующий раз мы добавим работу с уровнями запуска в новый проект и посмотрим, как это помогает управлять работой скрипта. А пока расскажите в комментариях, часто ли вы пользуетесь такими конструкциями или обходитесь вообще без них.

Текст:

Мария Глушанина

Обложка:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Мария Дронова

Соцсети:

Юлия Зубарева

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Вам может быть интересно
hard