__main__Top-level code environment顶级代码环境


In Python, the special name __main__ is used for two important constructs:在Python中,特殊名称__main__用于两个重要的构造:

  1. the name of the top-level environment of the program, which can be checked using the __name__ == '__main__' expression; and程序顶层环境的名称,可以使用__name__ == '__main__'表达式进行检查;和

  2. the __main__.py file in Python packages.Python包中的__main__.py文件。

Both of these mechanisms are related to Python modules; how users interact with them and how they interact with each other. 这两种机制都与Python模块相关;用户如何与他们互动以及他们如何彼此互动。They are explained in detail below. 下文将对其进行详细说明。If you’re new to Python modules, see the tutorial section Modules for an introduction.如果您是Python模块的新手,请参阅教程模块部分的介绍。

__name__ == '__main__'

When a Python module or package is imported, __name__ is set to the module’s name. 导入Python模块或包时,__name__设置为模块的名称。Usually, this is the name of the Python file itself without the .py extension:通常,这是Python文件本身的名称,不带.py扩展名:

>>> import configparser
>>> configparser.__name__
'configparser'

If the file is part of a package, __name__ will also include the parent package’s path:如果文件是包的一部分,__name__还将包括父包的路径:

>>> from concurrent.futures import process
>>> process.__name__
'concurrent.futures.process'

However, if the module is executed in the top-level code environment, its __name__ is set to the string '__main__'.但是,如果模块在顶级代码环境中执行,其__name__将设置为字符串'__main__'

What is the “top-level code environment”?什么是“顶级代码环境”?

__main__ is the name of the environment where top-level code is run. 运行顶层代码的环境的名称。“Top-level code” is the first user-specified Python module that starts running. “顶层代码”是第一个开始运行的用户指定的Python模块。It’s “top-level” because it imports all other modules that the program needs. 它是“顶级”的,因为它导入了程序所需的所有其他模块。Sometimes “top-level code” is called an entry point to the application.有时,“顶级代码”被称为应用程序的入口点

The top-level code environment can be:顶级代码环境可以是:

  • the scope of an interactive prompt:交互式提示的范围:

    >>> __name__
    '__main__'
  • the Python module passed to the Python interpreter as a file argument:Python模块作为文件参数传递给Python解释器:

    $ python3 helloworld.py
    Hello, world!
  • the Python module or package passed to the Python interpreter with the -m argument:通过-m参数传递给Python解释器的Python模块或包:

    $ python3 -m tarfile
    usage: tarfile.py [-h] [-v] (...)
  • Python code read by the Python interpreter from standard input:Python解释器从标准输入读取的Python代码:

    $ echo "import this" | python3
    The Zen of Python, by Tim Peters
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...
  • Python code passed to the Python interpreter with the -c argument:通过-c参数传递给Python解释器的Python代码:

    $ python3 -c "import this"
    The Zen of Python, by Tim Peters
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...

In each of these situations, the top-level module’s __name__ is set to '__main__'.在每种情况下,顶级模块的__name__都设置为'__main__'

As a result, a module can discover whether or not it is running in the top-level environment by checking its own __name__, which allows a common idiom for conditionally executing code when the module is not initialized from an import statement:因此,模块可以通过检查自己的__name__来发现它是否在顶级环境中运行,这允许在模块未从import语句初始化时有条件地执行代码:

if __name__ == '__main__':
# Execute when the module is not initialized from an import statement.
...

See also

For a more detailed look at how __name__ is set in all situations, see the tutorial section Modules.有关如何在所有情况下设置__name__的详细信息,请参阅教程模块部分。

Idiomatic Usage惯用用法

Some modules contain code that is intended for script use only, like parsing command-line arguments or fetching data from standard input. 某些模块包含仅供脚本使用的代码,如解析命令行参数或从标准输入中获取数据。If a module like this was imported from a different module, for example to unit test it, the script code would unintentionally execute as well.如果像这样的模块是从不同的模块导入的,例如为了对其进行单元测试,脚本代码也会无意中执行。

This is where using the if __name__ == '__main__' code block comes in handy. 这就是使用if __name__ == '__main__'代码块的地方。Code within this block won’t run unless the module is executed in the top-level environment.除非在顶级环境中执行模块,否则此块中的代码不会运行。

Putting as few statements as possible in the block below if __name___ == '__main__' can improve code clarity and correctness. 如果if __name___ == '__main__',则在下面的块中尽可能少地插入语句可以提高代码的清晰度和正确性。Most often, a function named main encapsulates the program’s primary behavior:通常,名为main的函数封装程序的主要行为:

# 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

Note that if the module didn’t encapsulate code inside the main function but instead put it directly within the if __name__ == '__main__' block, the phrase variable would be global to the entire module. 请注意,如果模块没有将代码封装在main函数中,而是将其直接放在if __name__ == '__main__'块中,则phrase变量将对整个模块是全局的。This is error-prone as other functions within the module could be unintentionally using the global variable instead of a local name. 这很容易出错,因为模块中的其他函数可能无意中使用了全局变量而不是本地名称。A main function solves this problem.main函数解决了这个问题。

Using a main function has the added benefit of the echo function itself being isolated and importable elsewhere. 使用main函数还有一个额外的好处,即echo函数本身是孤立的,并且可以在其他地方导入。When echo.py is imported, the echo and main functions will be defined, but neither of them will be called, because __name__ != '__main__'.导入echo.py时,将定义echomain函数,但它们都不会被调用,因为__name__ != '__main__'

Packaging Considerations包装注意事项

main functions are often used to create command-line tools by specifying them as entry points for console scripts. main函数通常用于创建命令行工具,将它们指定为控制台脚本的入口点。When this is done, pip inserts the function call into a template script, where the return value of main is passed into sys.exit(). 完成此操作后,pip将函数调用插入到模板脚本中,其中main的返回值被传递到sys.exit()中。For example:例如:

sys.exit(main())

Since the call to main is wrapped in sys.exit(), the expectation is that your function will return some value acceptable as an input to sys.exit(); typically, an integer or None (which is implicitly returned if your function does not have a return statement).由于对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.通过主动遵循这一约定,模块在直接运行(即python3 echo.py)时将具有与稍后将其打包为pip可安装包中的控制台脚本入口点时相同的行为。

In particular, be careful about returning strings from your main function. 尤其要注意从main函数返回字符串。sys.exit() will interpret a string argument as a failure message, so your program will have an exit code of 1, indicating failure, and the string will be written to sys.stderr. sys.exit()将字符串参数解释为失败消息,因此程序的退出代码为1,表示失败,字符串将写入sys.stderrThe echo.py example from earlier exemplifies using the sys.exit(main()) convention.前面的echo.py示例使用了sys.exit(main())约定。

See also

Python Packaging User Guide contains a collection of tutorials and references on how to distribute and install Python packages with modern tools.Python打包用户指南包含关于如何使用现代工具分发和安装Python包的教程和参考资料。

__main__.py in Python PackagesPython包中的__main__.py

If you are not familiar with Python packages, see section Packages of the tutorial. 如果您不熟悉Python包,请参阅教程的部分。Most commonly, the __main__.py file is used to provide a command-line interface for a package. 最常见的是,__main__.py文件用于为包提供命令行界面。Consider the following hypothetical package, “bandclass”:考虑以下假设包“bandclass”:

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

__main__.py will be executed when the package itself is invoked directly from the command line using the -m flag. 当使用-m标志从命令行直接调用包本身时,将执行__main__.pyFor example:例如:

$ python3 -m bandclass

This command will cause __main__.py to run. 此命令将导致__main__.py运行。How you utilize this mechanism will depend on the nature of the package you are writing, but in this hypothetical case, it might make sense to allow the teacher to search for students:您如何使用此机制将取决于您正在编写的包的性质,但在这种假设情况下,允许老师搜索学生可能是有意义的:

# 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)}')

Note that from .student import search_students is an example of a relative import. 注意,from .student import search_students是一个相对导入的示例。This import style can be used when referencing modules within a package. 当引用包中的模块时,可以使用此导入样式。For more details, see Intra-package References in the Modules section of the tutorial.有关详细信息,请参阅本教程模块部分中的包内参考

Idiomatic Usage惯用用法

The contents of __main__.py typically isn’t fenced with if __name__ == '__main__' blocks. __main__.py的内容通常不受if __name__ == '__main__'块的限制。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 used, an if __name__ == '__main__' block will still work as expected for a __main__.py file within a package, because its __name__ attribute will include the package’s path if imported:如果使用,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. 这对于zip文件根目录中的__main__.py文件无效。Hence, for consistency, minimal __main__.py like the venv one mentioned below are preferred.因此,为了保持一致性,最好使用最小的__main__.py,如下面提到的venv

See also

See venv for an example of a package with a minimal __main__.py in the standard library. 有关标准库中包含最小__main__.py的包的示例,请参阅venvIt doesn’t contain a if __name__ == '__main__' block. 它不包含if __name__ == '__main__'块。You can invoke it with python3 -m venv [directory].您可以使用python3 -m venv [directory]调用它。

See runpy for more details on the -m flag to the interpreter executable.有关解释器可执行文件的-m标志的更多详细信息,请参阅runpy

See zipapp for how to run applications packaged as .zip files. 有关如何运行打包为.zip文件的应用程序,请参阅zipappIn this case Python looks for a __main__.py file in the root directory of the archive.在本例中,Python在存档的根目录中查找__main__.py文件。

import __main__

Regardless of which module a Python program was started with, other modules running within that same program can import the top-level environment’s scope (namespace) by importing the __main__ module. 无论Python程序是用哪个模块启动的,同一程序中运行的其他模块都可以通过导入__main__模块来导入顶级环境的作用域(namespace)。This doesn’t import a __main__.py file but rather whichever module that received the special name '__main__'.这不会导入__main__.py文件,而是导入接收到特殊名称'__main__'的模块。

Here is an example module that consumes the __main__ namespace:下面是一个使用__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)

Example usage of this module could be as follows:该模块的示例用法如下:

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

Now, if we started our program, the result would look like this:现在,如果我们启动程序,结果将如下所示:

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

The exit code of the program would be 1, indicating an error. 程序的退出代码将为1,表示错误。Uncommenting the line with my_name = "Dinsdale" fixes the program and now it exits with status code 0, indicating success:my_name = "Dinsdale"取消对该行的注释将修复程序,现在它将退出,状态代码为0,表示成功:

$ python3 start.py
Dinsdale found in file /path/to/start.py

Note that importing __main__ doesn’t cause any issues with unintentionally running top-level code meant for script use which is put in the if __name__ == "__main__" block of the start module. 请注意,导入__main__不会导致无意中运行用于脚本的顶级代码出现任何问题,该顶级代码放在start模块的if __name__ == "__main__"块中。Why does this work?为什么这样做?

Python inserts an empty __main__ module in sys.modules at interpreter startup, and populates it by running top-level code. Python在解释器启动时在sys.modules中插入一个空__main__模块,并通过运行顶级代码填充它。In our example this is the start module which runs line by line and imports namely. 在示例中,这是一个start模块,它逐行运行,并导入namelyIn turn, namely imports __main__ (which is really start). 反过来,namely导入__main__(这是真正的start)。That’s an import cycle! 这是一个进口周期!Fortunately, since the partially populated __main__ module is present in sys.modules, Python passes that to namely. 幸运的是,由于sys.modules中存在部分填充的__main__模块,因此Python将其传递给namelySee Special considerations for __main__ in the import system’s reference for details on how this works.有关如何工作的详细信息,请参阅导入系统参考中__main__的特殊注意事项。

The Python REPL is another example of a “top-level environment”, so anything defined in the REPL becomes part of the __main__ scope: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

Note that in this case the __main__ scope doesn’t contain a __file__ attribute as it’s interactive.注意,在这种情况下,__main__作用域不包含__file__属性,因为它是交互式的。

The __main__ scope is used in the implementation of pdb and rlcompleter.__main__范围用于pdbrlcompleter的实现。