# `__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__'`.

### Що таке «середовище коду верхнього рівня»?

`__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__':
        # Execute when the module is not initialized from an import statement.
        ...

Дивись також

Для більш детального ознайомлення з тим, як `__name__` встановлюється в усіх ситуаціях, перегляньте розділ підручника Модулі.

### Ідіоматичне використання

Деякі модулі містять код, призначений лише для використання сценарієм, як-от аналіз аргументів командного рядка або отримання даних зі стандартного введення. Якщо подібний модуль було імпортовано з іншого модуля, наприклад, для модульного тестування, код сценарію також буде ненавмисно виконано.

Тут стане в нагоді використання блоку коду `if __name__ == '__main__''`. Код у цьому блоці не працюватиме, якщо модуль не буде виконано в середовищі верхнього рівня.

Putting as few statements as possible in the block below `if __name___ == '__main__'` can improve code clarity and correctness. Most often, a function named `main` encapsulates the program’s primary behavior:

    # 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).

By proactively following this convention ourselves, our module will have the same behavior when run directly (i.e. `python3 echo.py`) as it will have if we later package it as a console script entry-point in a pip-installable package.

Зокрема, будьте обережні щодо повернення рядків з вашої функції `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`. Наприклад:

    $ 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` є прикладом відносного імпорту. Цей стиль імпорту можна використовувати під час посилань на модулі в пакеті. Для отримання додаткової інформації перегляньте Внутрішньопакетні посилання у розділі Модулі підручника.

### Ідіоматичне використання

The contents of `__main__.py` typically isn’t fenced with `if __name__ == '__main__'` blocks. Instead, those files are kept short, functions to execute from other modules. Those other modules can then be easily unit-tested and are properly reusable.

Якщо використовується, блок `if __name__ == '__main__'` все одно працюватиме належним чином для файлу `__main__.py` у пакеті, тому що його атрибут `__name__` включатиме шлях до пакета, якщо імпортовано

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

This won’t work for `__main__.py` files in the root directory of a .zip file though. Hence, for consistency, minimal `__main__.py` like the `venv` one mentioned below are preferred.

Дивись також

See `venv` for an example of a package with a minimal `__main__.py` in the standard library. It doesn’t contain a `if __name__ == '__main__'` block. You can invoke it with `python -m venv [directory]`.

Перегляньте `runpy` для отримання додаткової інформації про прапорець `-m` для виконуваного файлу інтерпретатора.

Перегляньте `zipapp`, щоб дізнатися, як запускати програми, упаковані у файли .zip. У цьому випадку Python шукає файл `__main__.py` в кореневому каталозі архіву.

## `імпорт __main__`

Незалежно від того, з якого модуля була запущена програма Python, інші модулі, що працюють у цій же програмі, можуть імпортувати область верхнього рівня середовища (namespace), імпортуючи модуль `__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 inserts an empty `__main__` module in `sys.modules` at interpreter startup, and populates it by running top-level code. In our example this is the `start` module which runs line by line and imports `namely`. In turn, `namely` imports `__main__` (which is really `start`). That’s an import cycle! Fortunately, since the partially populated `__main__` module is present in `sys.modules`, Python passes that to `namely`. See Special considerations for __main__ in the import system’s reference for details on how this works.

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`.