__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__.
См. также
См. venv для примера пакета с минимальным файлом __main__.py в стандартной библиотеке. Он не содержит блок if __name__ == '__main__'. Вы можете вызвать его с помощью python -m venv [directory].
См. runpy для получения более подробной информации о флаге -m интерпретатора.
См. zipapp для получения информации о запуске приложений, упакованных в файлы .zip. В этом случае 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`!')
if '__file__' in dir(__main__):
print(__main__.my_name, "found in file", __main__.__file__)
else:
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 found in file /path/to/start.py
Обратите внимание, что импорт __main__ не вызывает никаких проблем с непреднамеренным запуском кода верхнего уровня, предназначенного для использования в скриптах, который помещён в блок if __name__ == "__main__" модуля start. Почему это работает?
Python вставляет пустой модуль __main__ в sys.modules при запуске интерпретатора и заполняет его, выполняя код верхнего уровня. В нашем примере это модуль start, который выполняется построчно и импортирует namely. В свою очередь, namely импортирует __main__ (который фактически является start). Это цикл импорта! К счастью, так как частично заполненный модуль __main__ присутствует в sys.modules, Python передаёт его namely. Подробности о том, как это работает, см. в разделе Особые соображения для __main__ справочника по системе импорта.
Python REPL — ещё один пример «среды верхнего уровня», поэтому всё, что определено в REPL, становится частью пространства имён __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__ не содержит атрибута __file__ , так как это интерактивный режим.
Пространство имён __main__ используется в реализации pdb и rlcompleter.
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/__main__.html