__main__ — Среда выполнения кода верхнего уровня
В Python специальное имя __main__ используется для двух важных конструкций:
- имя среды верхнего уровня программы, которое можно проверить с помощью выражения
__name__ == '__main__'; и - файл
__main__.pyв пакетах Python.
Оба этих механизма связаны с модулями Python, с тем, как пользователи взаимодействуют с ними и как они взаимодействуют друг с другом. Ниже они подробно рассматриваются. Если вы только знакомитесь с модулями Python, ознакомьтесь с вводным разделом руководства Модули.
__name__ == '__main__'
При импорте модуля или пакета Python значению __name__ присваивается имя модуля. Обычно это имя самого файла Python без расширения .py:
>>> import configparser >>> configparser.__name__ 'configparser'
Если файл является частью пакета, __name__ также будет содержать путь родительского пакета:
>>> from concurrent.futures import process >>> process.__name__ 'concurrent.futures.process'
Однако если модуль выполняется в среде кода верхнего уровня, его __name__ присваивается строковое значение '__main__'.
Что такое «среда выполнения кода верхнего уровня»?
__main__ — это имя среды, в которой выполняется код верхнего уровня. «Код верхнего уровня» — это первый указанный пользователем модуль Python, выполнение которого начинается. Он называется «верхним уровнем», потому что импортирует все остальные модули, необходимые программе. Иногда «код верхнего уровня» называют точкой входа приложения.
Средой выполнения кода верхнего уровня может быть:
-
область интерактивного приглашения:
>>> __name__ '__main__'
-
модуль Python, переданный интерпретатору Python в качестве аргумента-файла:
$ python helloworld.py Hello, world!
-
модуль или пакет Python, переданный интерпретатору Python с аргументом
-m:$ python -m tarfile usage: tarfile.py [-h] [-v] (...)
-
код Python, прочитанный интерпретатором Python из стандартного ввода:
$ echo "import this" | python The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. ...
-
код Python, переданный интерпретатору Python с аргументом
-c:$ python -c "import this" The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. ...
В каждом из этих случаев атрибут __name__ модуля верхнего уровня получает значение '__main__'.
Таким образом, модуль может определить, выполняется ли он в среде верхнего уровня, проверив собственный __name__. Это позволяет использовать распространённый идиоматический приём: условно выполнять код, если модуль не инициализирован оператором импорта:
if __name__ == '__main__':
# Execute when the module is not initialized from an import statement.
...
См. также
Подробнее о том, как значение __name__ задаётся в разных ситуациях, см. в разделе руководства Модули.
Идиоматическое использование
Некоторые модули содержат код, предназначенный только для запуска в виде скрипта, например разбор аргументов командной строки или получение данных из стандартного ввода. Если такой модуль импортировать из другого модуля, например для модульного тестирования, код скрипта тоже выполнится, хотя этого не предполагалось.
В этом случае полезен блок кода if __name__ == '__main__'. Код внутри этого блока выполняется только тогда, когда модуль запущен в среде верхнего уровня.
Чем меньше инструкций в блоке ниже if __name__ ==
'__main__', тем понятнее и надёжнее код. Чаще всего основное поведение программы заключено в функции с именем main:
# echo.py
import shlex
import sys
def echo(phrase: str) -> None:
"""A dummy wrapper around print."""
# for demonstration purposes, you can imagine that there is some
# valuable and reusable logic inside this function
print(phrase)
def main() -> int:
"""Echo the input arguments to standard output"""
phrase = shlex.join(sys.argv)
echo(phrase)
return 0
if __name__ == '__main__':
sys.exit(main()) # next section explains the use of sys.exit
Обратите внимание: если бы код модуля не был заключён в функцию main, а располагался непосредственно в блоке if __name__ == '__main__', переменная phrase была бы глобальной для всего модуля. Это может привести к ошибкам, поскольку другие функции модуля могут случайно использовать глобальную переменную вместо локального имени. Функция main решает эту проблему.
Использование функции main также позволяет изолировать саму функцию echo и импортировать её из других мест. При импорте echo.py функции echo и main будут определены, но ни одна из них не будет вызвана, поскольку __name__ != '__main__'.
Особенности упаковки
Функции main часто используются для создания инструментов командной строки: их указывают в качестве точек входа консольных скриптов. В этом случае pip помещает вызов функции в шаблон скрипта, где возвращаемое значение main передаётся в sys.exit(). Например:
sys.exit(main())
Поскольку вызов main обёрнут в sys.exit(), предполагается, что ваша функция вернёт значение, допустимое в качестве аргумента для sys.exit(); обычно это целое число или None (которое неявно возвращается, если в функции нет инструкции return).
Если мы заранее будем следовать этому соглашению, наш модуль будет вести себя одинаково при непосредственном запуске (то есть python echo.py) и при последующей упаковке в виде точки входа консольного скрипта в устанавливаемом с помощью pip пакете.
В частности, будьте осторожны с возвратом строк из функции main. sys.exit() интерпретирует строковый аргумент как сообщение об ошибке, поэтому программа завершится с кодом 1, указывающим на ошибку, а строка будет записана в sys.stderr. В приведённом ранее примере echo.py показано использование соглашения sys.exit(main()).
См. также
Руководство пользователя по упаковке Python содержит подборку руководств и справочных материалов о распространении и установке пакетов Python с помощью современных инструментов.
__main__.py в пакетах Python
Если вы не знакомы с пакетами Python, см. раздел Пакеты руководства. Чаще всего файл __main__.py используется для предоставления интерфейса командной строки пакета. Рассмотрим следующий гипотетический пакет «bandclass»:
bandclass ├── __init__.py ├── __main__.py └── student.py
__main__.py будет выполнен, если вызвать сам пакет непосредственно из командной строки с флагом -m. Например:
$ python -m bandclass
Эта команда приведёт к запуску __main__.py. Способ использования этого механизма зависит от назначения создаваемого вами пакета, но в данном гипотетическом случае учителю может понадобиться возможность искать учеников:
# bandclass/__main__.py
import sys
from .student import search_students
student_name = sys.argv[1] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')
Обратите внимание, что from .student import search_students — это пример относительного импорта. Такой стиль импорта можно использовать при обращении к модулям внутри пакета. Подробнее см. в разделе Ссылки внутри пакета раздела Модули руководства.
Идиоматическое использование
Содержимое __main__.py обычно не помещают в блок if __name__ == '__main__'. Вместо этого такие файлы делают короткими и импортируют в них функции из других модулей для выполнения. Эти другие модули можно легко подвергать модульному тестированию, и их можно правильно использовать повторно.
Если добавить блок if __name__ == '__main__', он будет работать ожидаемым образом в файле __main__.py внутри пакета, поскольку при импорте его атрибут __name__ будет содержать путь пакета:
>>> import asyncio.__main__ >>> asyncio.__main__.__name__ 'asyncio.__main__'
Однако это не сработает для файлов __main__.py в корневом каталоге файла .zip. Поэтому для единообразия предпочтителен минимальный __main__.py без проверки __name__.
См. также
Пример пакета с минимальным __main__.py в стандартной библиотеке см. в разделе venv. Он не содержит блока if __name__ == '__main__'. Его можно вызвать с помощью python -m venv [directory].
Подробнее о флаге -m исполняемого файла интерпретатора см. в разделе runpy.
О запуске приложений, упакованных в файлы .zip, см. в разделе zipapp. В этом случае Python ищет файл __main__.py в корневом каталоге архива.
import __main__
Независимо от того, с какого модуля была запущена программа Python, другие модули, работающие в той же программе, могут импортировать область видимости (пространство имён) среды верхнего уровня, импортировав модуль __main__. При этом импортируется не файл __main__.py, а модуль, которому присвоено специальное имя '__main__'.
Вот пример модуля, использующего пространство имён __main__:
# namely.py
import __main__
def did_user_define_their_name():
return 'my_name' in dir(__main__)
def print_user_name():
if not did_user_define_their_name():
raise ValueError('Define the variable `my_name`!')
print(__main__.my_name)
Пример использования этого модуля:
# start.py
import sys
from namely import print_user_name
# my_name = "Dinsdale"
def main():
try:
print_user_name()
except ValueError as ve:
return str(ve)
if __name__ == "__main__":
sys.exit(main())
Теперь, если запустить программу, результат будет выглядеть так:
$ python start.py Define the variable `my_name`!
Код завершения программы будет равен 1, что указывает на ошибку. Если раскомментировать строку с my_name = "Dinsdale", программа заработает и завершится с кодом 0, указывающим на успешное выполнение:
$ python start.py Dinsdale
Обратите внимание, что импорт __main__ не приводит к непреднамеренному выполнению кода верхнего уровня, предназначенного для запуска в виде скрипта и помещённого в блок if __name__ == "__main__" модуля start. Почему это работает?
При запуске интерпретатора Python помещает пустой модуль __main__ в sys.modules и заполняет его, выполняя код верхнего уровня. В нашем примере это модуль start, который выполняется построчно и импортирует namely. В свою очередь, namely импортирует __main__ (который на самом деле является start). Это цикл импорта! К счастью, поскольку частично заполненный модуль __main__ уже находится в sys.modules, Python передаёт его в namely. Подробнее об этом см. в справочнике по системе импорта в разделе Особенности __main__.
Интерактивная оболочка Python — ещё один пример «среды верхнего уровня», поэтому всё определённое в ней становится частью области видимости __main__:
>>> import namely >>> namely.did_user_define_their_name() False >>> namely.print_user_name() Traceback (most recent call last): ... ValueError: Define the variable `my_name`! >>> my_name = 'Jabberwocky' >>> namely.did_user_define_their_name() True >>> namely.print_user_name() Jabberwocky
Область видимости __main__ используется при реализации pdb и rlcompleter.
© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/__main__.html