Документация Python неофициальный перевод
Содержание страницы

__main__ – Среда кода верхнего уровня__main__ – Top-level code environment


В 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__'.

Что такое «среда кода верхнего уровня»?What is the “top-level code environment”?

__main__ – это имя среды, в которой выполняется код верхнего уровня. «Код верхнего уровня» – это первый указанный пользователем модуль Python, который запускается. Он называется «верхнего уровня», потому что импортирует все остальные модули, необходимые программе. Иногда «код верхнего уровня» называют точкой входа в приложение.

Средой кода верхнего уровня может быть:

  • область интерактивного приглашения:

    >>> __name__
    '__main__'
    
  • модуль Python, переданный интерпретатору Python в качестве аргумента-файла:

    $ python3 helloworld.py
    Hello, world!
    
  • модуль или пакет Python, переданные интерпретатору Python с аргументом -m:

    $ python3 -m tarfile
    usage: tarfile.py [-h] [-v] (...)
    
  • код Python, читаемый интерпретатором Python из стандартного ввода:

    $ echo "import this" | python3
    The Zen of Python, by Tim Peters
    
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...
    
  • код Python, переданный интерпретатору Python с аргументом -c:

    $ python3 -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__':
    # Выполняется, когда модуль не инициализирован из оператора import.
    ...

См. также

Более подробно о том, как __name__ устанавливается во всех ситуациях, см. в разделе учебного пособия Модули.

Идиоматическое использованиеIdiomatic Usage

Некоторые модули содержат код, предназначенный только для использования в скриптах, например разбор аргументов командной строки или получение данных из стандартного ввода. Если такой модуль импортируется из другого модуля, например для модульного тестирования, код скрипта также непреднамеренно выполнится.

Здесь пригождается использование блока кода if __name__ == '__main__'. Код внутри этого блока не будет выполняться, пока модуль не будет запущен в среде верхнего уровня.

Размещение как можно меньшего количества операторов в блоке ниже if __name___ == '__main__' может улучшить ясность и корректность кода. Чаще всего функция с именем main инкапсулирует основное поведение программы:

# echo.py

import shlex
import sys

def echo(phrase: str) -> None:
   """Пустая обёртка вокруг print."""
   # для целей демонстрации можно представить, что существует некоторая
   # ценная и повторно используемая логика внутри этой функции
   print(phrase)

def main() -> int:
    """Выводит входные аргументы в стандартный вывод"""
    phrase = shlex.join(sys.argv)
    echo(phrase)
    return 0

if __name__ == '__main__':
    sys.exit(main())  # в следующем разделе объясняется использование sys.exit

Обратите внимание: если бы модуль не инкапсулировал код внутри функции main, а поместил бы его непосредственно в блок if __name__ == '__main__', переменная phrase была бы глобальной для всего модуля. Это чревато ошибками, так как другие функции в модуле могли бы случайно использовать глобальную переменную вместо локального имени. Функция main решает эту проблему.

Использование функции main даёт дополнительное преимущество: сама функция echo изолируется и может быть импортирована в другом месте. При импорте echo.py функции echo и main будут определены, но ни одна из них не будет вызвана, потому что __name__ != '__main__'.

Особенности упаковкиPackaging Considerations

Функции main часто используются для создания инструментов командной строки путём указания их в качестве точек входа для консольных скриптов. Когда это делается, pip вставляет вызов функции в шаблонный скрипт, где возвращаемое значение main передаётся в sys.exit(). Например:

sys.exit(main())

Поскольку вызов main обёрнут в sys.exit(), ожидается, что функция вернёт значение, приемлемое в качестве ввода для sys.exit(); обычно это целое число или None (которое неявно возвращается, если в функции нет оператора return).

Следуя этому соглашению заранее, модуль будет вести себя одинаково при прямом запуске (т.е. python3 echo.py) и при последующей упаковке в качестве точки входа консольного скрипта в пакет, устанавливаемый через pip.

В частности, будьте осторожны с возвратом строк из функции main. sys.exit() интерпретирует строковый аргумент как сообщение об ошибке, поэтому программа получит код возврата 1, указывающий на сбой, а строка будет записана в sys.stderr. Пример echo.py из предыдущего демонстрирует использование соглашения sys.exit(main()).

См. также

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

__main__.py в пакетах Python__main__.py in Python Packages

Если вы не знакомы с пакетами Python, обратитесь к разделу Пакеты учебного пособия. Чаще всего файл __main__.py используется для предоставления интерфейса командной строки для пакета. Рассмотрим следующий гипотетический пакет «bandclass»:

bandclass
  ├── __init__.py
  ├── __main__.py
  └── student.py

__main__.py будет выполнен, когда сам пакет вызывается напрямую из командной строки с помощью флага -m. Например:

$ python3 -m bandclass

Эта команда запустит __main__.py. То, как вы используете этот механизм, зависит от характера пакета, который вы пишете, но в этом гипотетическом случае может иметь смысл позволить учителю искать учеников:

# bandclass/__main__.py

import sys
from .student import search_students

student_name = sys.argv[2] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')

Обратите внимание, что from .student import search_students – это пример относительного импорта. Этот стиль импорта можно использовать при обращении к модулям внутри пакета. Подробнее см. Ссылки внутри пакета в разделе Модули учебного пособия.

Идиоматическое использованиеIdiomatic Usage

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

Если используется, блок if __name__ == '__main__' всё равно будет работать как ожидается для файла __main__.py внутри пакета, потому что его атрибут __name__ будет включать путь к пакету при импорте:

>>> import asyncio.__main__
>>> asyncio.__main__.__name__
'asyncio.__main__'

Однако это не будет работать для файлов __main__.py в корневом каталоге .zip-файла. Поэтому для единообразия предпочтительны минимальные __main__.py, например venv, упомянутые ниже.

См. также

См. 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())

Теперь, если бы мы запустили нашу программу, результат выглядел бы так:

$ python3 start.py
Define the variable `my_name`!

Код завершения программы был бы равен 1, что указывает на ошибку. Раскомментирование строки с my_name = "Dinsdale" исправляет программу, и теперь она завершается с кодом состояния 0, что указывает на успех:

$ python3 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__ в справочнике по системе импорта для подробностей о том, как это работает.

REPL Python – это ещё один пример «среды верхнего уровня», поэтому всё, определённое в 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.