Spec-Zone.ru › Python 3.13

__main__ — верхнеуровневая среда выполнения кода

В Python специальное имя __main__ используется для двух важных конструкций:

  1. имени верхнеуровневой среды программы, которое можно проверить с помощью выражения __name__ == '__main__'; и
  2. файла __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__'. Вместо этого такие файлы оставляют короткими и импортируют из них функции, выполняемые в других модулях. Эти другие модули можно легко покрыть модульными тестами, и их удобно повторно использовать.

Если в файле __main__.py внутри пакета используется блок if __name__ == '__main__', он всё равно будет работать как ожидается, поскольку при импорте его атрибут __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`!')

    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 — ещё один пример «верхнеуровневой среды», поэтому всё определённое в ней становится частью области видимости __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–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/__main__.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API