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

__main__.md

280 строк · 19.1 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3/library/__main__.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `__main__` – Среда кода верхнего уровня89---1011В Python специальное имя `__main__` используется для двух важных конструкций:12131. имя среды верхнего уровня программы, которое можно проверить с помощью выражения `__name__ == '__main__'`; и142. файл `__main__.py` в пакетах Python.1516Оба этих механизма связаны с модулями Python: как пользователи взаимодействуют с ними и как модули взаимодействуют друг с другом. Они подробно описаны ниже. Если вы новичок в работе с модулями Python, см. раздел учебного пособия [Модули](https://python-all.ru/3/tutorial/modules.html#tut-modules) для введения.1718## `__name__ == '__main__'`1920Когда модуль или пакет Python импортируется, `__name__` устанавливается в имя модуля. Обычно это имя самого файла Python без расширения `.py`:2122```python23>>> import configparser24>>> configparser.__name__25'configparser'26```2728Если файл является частью пакета, `__name__` также будет включать путь родительского пакета:2930```python31>>> from concurrent.futures import process32>>> process.__name__33'concurrent.futures.process'34```3536Однако если модуль выполняется в среде кода верхнего уровня, его `__name__` устанавливается в строку `'__main__'`.3738### Что такое «среда кода верхнего уровня»?3940`__main__` – это имя среды, в которой выполняется код верхнего уровня. «Код верхнего уровня» – это первый указанный пользователем модуль Python, который запускается. Он называется «верхнего уровня», потому что импортирует все остальные модули, необходимые программе. Иногда «код верхнего уровня» называют *точкой входа* в приложение.4142Средой кода верхнего уровня может быть:4344- область интерактивного приглашения:4546  ```python47  >>> __name__48  '__main__'49  ```50- модуль Python, переданный интерпретатору Python в качестве аргумента-файла:5152  ```console53  $ python helloworld.py54  Hello, world!55  ```56- модуль или пакет Python, переданные интерпретатору Python с аргументом [`-m`](https://python-all.ru/3/using/cmdline.html#cmdoption-m):5758  ```console59  $ python -m tarfile60  usage: tarfile.py [-h] [-v] (...)61  ```62- код Python, читаемый интерпретатором Python из стандартного ввода:6364  ```console65  $ echo "import this" | python66  The Zen of Python, by Tim Peters6768  Beautiful is better than ugly.69  Explicit is better than implicit.70  ...71  ```72- код Python, переданный интерпретатору Python с аргументом [`-c`](https://python-all.ru/3/using/cmdline.html#cmdoption-c):7374  ```console75  $ python -c "import this"76  The Zen of Python, by Tim Peters7778  Beautiful is better than ugly.79  Explicit is better than implicit.80  ...81  ```8283В каждой из этих ситуаций `__name__` модуля верхнего уровня устанавливается в `'__main__'`.8485В результате модуль может определить, выполняется ли он в среде верхнего уровня, проверив свой собственный `__name__`, что позволяет использовать распространённый идиоматический приём для условного выполнения кода, когда модуль инициализируется не из оператора импорта:8687```python88if __name__ == '__main__':89    # Выполняется, когда модуль не инициализирован из оператора import.90    ...91```9293> **См. также**94>95> Более подробно о том, как `__name__` устанавливается во всех ситуациях, см. в разделе учебного пособия [Модули](https://python-all.ru/3/tutorial/modules.html#tut-modules).9697### Идиоматическое использование9899Некоторые модули содержат код, предназначенный только для использования в скриптах, например разбор аргументов командной строки или получение данных из стандартного ввода. Если такой модуль импортируется из другого модуля, например для модульного тестирования, код скрипта также непреднамеренно выполнится.100101Здесь пригождается использование блока кода `if __name__ == '__main__'`. Код внутри этого блока не будет выполняться, пока модуль не будет запущен в среде верхнего уровня.102103Размещение как можно меньшего количества операторов в блоке ниже `if __name__ == '__main__'` может улучшить ясность и корректность кода. Чаще всего функция с именем `main` инкапсулирует основное поведение программы:104105```python106# echo.py107108import shlex109import sys110111def echo(phrase: str) -> None:112   """Пустая обёртка вокруг print."""113   # для целей демонстрации можно представить, что существует некоторая114   # ценная и повторно используемая логика внутри этой функции115   print(phrase)116117def main() -> int:118    """Выводит входные аргументы в стандартный вывод"""119    phrase = shlex.join(sys.argv)120    echo(phrase)121    return 0122123if __name__ == '__main__':124    sys.exit(main())  # в следующем разделе объясняется использование sys.exit125```126127Обратите внимание: если бы модуль не инкапсулировал код внутри функции `main`, а поместил бы его непосредственно в блок `if __name__ == '__main__'`, переменная `phrase` была бы глобальной для всего модуля. Это чревато ошибками, так как другие функции в модуле могли бы случайно использовать глобальную переменную вместо локального имени. Функция `main` решает эту проблему.128129Использование функции `main` даёт дополнительное преимущество: сама функция `echo` изолируется и может быть импортирована в другом месте. При импорте `echo.py` функции `echo` и `main` будут определены, но ни одна из них не будет вызвана, потому что `__name__ != '__main__'`.130131### Особенности упаковки132133Функции `main` часто используются для создания инструментов командной строки путём указания их в качестве точек входа для консольных скриптов. Когда это делается, [pip](https://python-all.ru/3/library/__main__.html) вставляет вызов функции в шаблонный скрипт, где возвращаемое значение `main` передаётся в [`sys.exit()`](https://python-all.ru/3/library/sys.html#sys.exit). Например:134135```python136sys.exit(main())137```138139Поскольку вызов `main` обёрнут в [`sys.exit()`](https://python-all.ru/3/library/sys.html#sys.exit), ожидается, что функция вернёт значение, приемлемое в качестве ввода для `sys.exit()`; обычно это целое число или `None` (которое неявно возвращается, если в функции нет оператора return).140141Следуя этому соглашению заранее, модуль будет вести себя одинаково при прямом запуске (т.е. `python echo.py`) и при последующей упаковке в качестве точки входа консольного скрипта в пакет, устанавливаемый через pip.142143В частности, будьте осторожны с возвратом строк из функции `main`. [`sys.exit()`](https://python-all.ru/3/library/sys.html#sys.exit) интерпретирует строковый аргумент как сообщение об ошибке, поэтому программа получит код возврата `1`, указывающий на сбой, а строка будет записана в [`sys.stderr`](https://python-all.ru/3/library/sys.html#sys.stderr). Пример `echo.py` из предыдущего демонстрирует использование соглашения `sys.exit(main())`.144145> **См. также**146>147> [Руководство пользователя по упаковке Python](https://python-all.ru/3/library/__main__.html) содержит набор учебных пособий и справочных материалов о том, как распространять и устанавливать пакеты Python с помощью современных инструментов.148149## `__main__.py` в пакетах Python150151Если вы не знакомы с пакетами Python, обратитесь к разделу [Пакеты](https://python-all.ru/3/tutorial/modules.html#tut-packages) учебного пособия. Чаще всего файл `__main__.py` используется для предоставления интерфейса командной строки для пакета. Рассмотрим следующий гипотетический пакет «bandclass»:152153```text154bandclass155  ├── __init__.py156  ├── __main__.py157  └── student.py158```159160`__main__.py` будет выполнен, когда сам пакет вызывается напрямую из командной строки с помощью флага [`-m`](https://python-all.ru/3/using/cmdline.html#cmdoption-m). Например:161162```console163$ python -m bandclass164```165166Эта команда запустит `__main__.py`. То, как вы используете этот механизм, зависит от характера пакета, который вы пишете, но в этом гипотетическом случае может иметь смысл позволить учителю искать учеников:167168```python169# bandclass/__main__.py170171import sys172from .student import search_students173174student_name = sys.argv[1] if len(sys.argv) >= 2 else ''175print(f'Found student: {search_students(student_name)}')176```177178Обратите внимание, что `from .student import search_students` – это пример относительного импорта. Этот стиль импорта можно использовать при обращении к модулям внутри пакета. Подробнее см. [Ссылки внутри пакета](https://python-all.ru/3/tutorial/modules.html#intra-package-references) в разделе [Модули](https://python-all.ru/3/tutorial/modules.html#tut-modules) учебного пособия.179180### Идиоматическое использование181182Содержимое `__main__.py` обычно не обрамляется блоком `if __name__ == '__main__'`. Вместо этого такие файлы делают короткими и импортируют функции для выполнения из других модулей. Эти другие модули затем можно легко модульно тестировать, и они надлежащим образом пригодны для повторного использования.183184Если используется, блок `if __name__ == '__main__'` всё равно будет работать как ожидается для файла `__main__.py` внутри пакета, потому что его атрибут `__name__` будет включать путь к пакету при импорте:185186```python187>>> import asyncio.__main__188>>> asyncio.__main__.__name__189'asyncio.__main__'190```191192Однако это не будет работать для файлов `__main__.py` в корневом каталоге файла `.zip`. Поэтому для согласованности предпочтительнее минимальный `__main__.py` без проверки `__name__`.193194> **См. также**195>196> См. [`venv`](https://python-all.ru/3/library/venv.html#module-venv) для примера пакета с минимальным `__main__.py` в стандартной библиотеке. Он не содержит блока `if __name__ == '__main__'`. Вы можете вызвать его с помощью `python -m venv [directory]`.197>198> См. [`runpy`](https://python-all.ru/3/library/runpy.html#module-runpy) для получения более подробной информации о флаге [`-m`](https://python-all.ru/3/using/cmdline.html#cmdoption-m) исполняемого файла интерпретатора.199>200> См. [`zipapp`](https://python-all.ru/3/library/zipapp.html#module-zipapp) о том, как запускать приложения, упакованные как файлы *.zip*. В этом случае Python ищет файл `__main__.py` в корневом каталоге архива.201202## `import __main__`203204Независимо от того, с какого модуля была запущена программа Python, другие модули, работающие в той же программе, могут импортировать область видимости верхнего уровня ([пространство имён](https://python-all.ru/3/glossary.html#term-namespace)), импортировав модуль `__main__`. При этом импортируется не файл `__main__.py`, а тот модуль, который получил специальное имя `'__main__'`.205206Вот пример модуля, который использует пространство имён `__main__`:207208```python209# namely.py210211import __main__212213def did_user_define_their_name():214    return 'my_name' in dir(__main__)215216def print_user_name():217    if not did_user_define_their_name():218        raise ValueError('Define the variable `my_name`!')219220    print(__main__.my_name)221```222223Пример использования этого модуля может быть следующим:224225```python226# start.py227228import sys229230from namely import print_user_name231232# my_name = "Dinsdale"233234def main():235    try:236        print_user_name()237    except ValueError as ve:238        return str(ve)239240if __name__ == "__main__":241    sys.exit(main())242```243244Теперь, если бы мы запустили нашу программу, результат выглядел бы так:245246```console247$ python start.py248Define the variable `my_name`!249```250251Код завершения программы был бы равен 1, что указывает на ошибку. Раскомментирование строки с `my_name = "Dinsdale"` исправляет программу, и теперь она завершается с кодом состояния 0, что указывает на успех:252253```console254$ python start.py255Dinsdale256```257258Обратите внимание, что импорт `__main__` не вызывает проблем с непреднамеренным запуском кода верхнего уровня, предназначенного для использования в сценариях, который помещён в блок `if __name__ == "__main__"` модуля `start`. Почему это работает?259260Python вставляет пустой модуль `__main__` в [`sys.modules`](https://python-all.ru/3/library/sys.html#sys.modules) при запуске интерпретатора и заполняет его, выполняя код верхнего уровня. В нашем примере это модуль `start`, который выполняется строка за строкой и импортирует `namely`. В свою очередь, `namely` импортирует `__main__` (что на самом деле является `start`). Это циклический импорт! К счастью, поскольку частично заполненный модуль `__main__` присутствует в `sys.modules`, Python передаёт его в `namely`. См. [Особые соображения для \_\_main\_\_](https://python-all.ru/3/reference/import.html#import-dunder-main) в справочнике по системе импорта для подробностей о том, как это работает.261262REPL Python – это ещё один пример «среды верхнего уровня», поэтому всё, определённое в REPL, становится частью области видимости `__main__`:263264```python265>>> import namely266>>> namely.did_user_define_their_name()267False268>>> namely.print_user_name()269Traceback (most recent call last):270...271ValueError: Define the variable `my_name`!272>>> my_name = 'Jabberwocky'273>>> namely.did_user_define_their_name()274True275>>> namely.print_user_name()276Jabberwocky277```278279Область видимости `__main__` используется в реализации [`pdb`](https://python-all.ru/3/library/pdb.html#module-pdb) и [`rlcompleter`](https://python-all.ru/3/library/rlcompleter.html#module-rlcompleter).280