__main__
— Top-level code environment顶级代码环境¶
In Python, the special name 在Python中,特殊名称__main__
is used for two important constructs:__main__
用于两个重要的构造:
the name of the top-level environment of the program, which can be checked using the程序顶层环境的名称,可以使用__name__ == '__main__'
expression; and__name__ == '__main__'
表达式进行检查;和thePython包中的__main__.py
file in Python packages.__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, 导入Python模块或包时,__name__
is set to the module’s name. __name__
设置为模块的名称。Usually, this is the name of the Python file itself without the 通常,这是Python文件本身的名称,不带.py
extension:.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.
...
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
时,将定义echo
和main
函数,但它们都不会被调用,因为__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 完成此操作后,pip将函数调用插入到模板脚本中,其中main
is passed into sys.exit()
. 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.stderr
。The 前面的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
¶
__main__.py
in Python PackagesIf 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__.py
。For 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 这对于zip文件根目录中的__main__.py
files in the root directory of a .zip file though. __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
的包的示例,请参阅venv
。It 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 有关如何运行打包为.zip文件的应用程序,请参阅zipapp
for how to run applications packaged as .zip files. zipapp
。In this case Python looks for a 在本例中,Python在存档的根目录中查找__main__.py
file in the root directory of the archive.__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 无论Python程序是用哪个模块启动的,同一程序中运行的其他模块都可以通过导入__main__
module. __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 Python在解释器启动时在__main__
module in sys.modules
at interpreter startup, and populates it by running top-level code. sys.modules
中插入一个空__main__
模块,并通过运行顶级代码填充它。In our example this is the 在示例中,这是一个start
module which runs line by line and imports namely
. start
模块,它逐行运行,并导入namely
。In 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将其传递给namely
。See 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 Python REPL是“顶级环境”的另一个示例,因此REPL中定义的任何内容都将成为__main__
scope:__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__
范围用于pdb
和rlcompleter
的实现。