__main__
— Top-level code environment¶
У Python спеціальна назва __main__
використовується для двох важливих конструкцій:
ім’я середовища верхнього рівня програми, яке можна перевірити за допомогою виразу
__name__ == '__main__'
; іфайл
__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[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__'
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
.