__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 як аргумент файлу:

    $ 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__''. Код у цьому блоці не працюватиме, якщо модуль не буде виконано в середовищі верхнього рівня.

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. python 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. Наприклад:

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

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

The content of __main__.py typically isn’t fenced with an if __name__ == '__main__' block. Instead, those files are kept short and import 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__'

Однак це не працюватиме для файлів __main__.py у кореневому каталозі файлу .zip. Тому для узгодженості бажано використовувати мінімальний __main__.py, наприклад venv, згаданий нижче.

Дивись також

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())

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

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