__main__ --- 最高层级代码环境— Python 3.10.7 說明文件
文章推薦指數: 80 %
在Python 中,特殊名称 __main__ 被用于两个重要的构造: 程序的最高层级环境的名称,可以 ... bandclass ├── __init__.py ├── __main__.py └── student.py.
瀏覽
索引
模組|
下一頁|
上一頁|
Python»
3.10.7Documentation»
Python標準函式庫(StandardLibrary)»
Python运行时服务»
__main__---最高层级代码环境
|
__main__---最高层级代码环境¶
在Python中,特殊名称__main__被用于两个重要的构造:
程序的最高层级环境的名称,可以使用__name__=='__main__'表达式来检查它;以及
Python包中的__main__.py文件。
这两种机制都有Python模块有关;用户如何与它们交互以及它们之间如何交互。
下文将进行详细说明。
如果你还不了解Python模块,请查看教程模組(Module)一节的介绍。
__name__=='__main__'¶
当一个Python模块或包被导入时,__name__会被设为模块的名称。
通常,这将是Python文件本身的名称去掉.py后缀:
>>>importconfigparser
>>>configparser.__name__
'configparser'
如果文件是包的组成部分,则__name__还将包括父包的路径:
>>>fromconcurrent.futuresimportprocess
>>>process.__name__
'concurrent.futures.process'
不过,如果模块是在最高层级代码环境中执行的,则它的__name__会被设为字符串'__main__'。
什么是“最高层级代码环境”?¶
__main__是最高层级代码运行所在环境的名称。
“最高层级代码”即用户指定最先启动运行的Python模块。
它被称为“最高层级”是因为它将导入程序所需的所有其他模块。
有时“最高层级代码”也被称为应用的入口点。
最高层级代码环境可以是:
一个交互提示符的作用域:
>>>__name__
'__main__'
作为文件参数传给Python解释器的Python模块:
$python3helloworld.py
Hello,world!
作为-m参数传给Python解释器的Python模块或包:
$python3-mtarfile
usage:tarfile.py[-h][-v](...)
Python解释器从标准输入中读取的Python代码:
$echo"importthis"|python3
TheZenofPython,byTimPeters
Beautifulisbetterthanugly.
Explicitisbetterthanimplicit.
...
作为-c参数传递给Python解释器的Python代码:
$python3-c"importthis"
TheZenofPython,byTimPeters
Beautifulisbetterthanugly.
Explicitisbetterthanimplicit.
...
在以上每个情形中,顶级模块的__name__被设置为'__main__'。
因此,一个模块可以通过检查自己的__name__,来发现它是否在顶层环境中运行。
这是允许在模块没有从导入语句中初始化的情况下,有条件地执行代码的一个常见的语句:
if__name__=='__main__':
#Executewhenthemoduleisnotinitializedfromanimportstatement.
...
也參考
关于在所有情况下__name__是如何设置的细节,请看教程部分模組(Module)。
常见用法¶
有些模块包含了仅供脚本使用的代码,比如解析命令行参数或从标准输入获取数据。
如果这样的模块被从不同的模块中导入,例如为了单元测试,脚本代码也会无意中执行。
这就是if__name__=='__main__'代码块的用武之地。
除非模块在顶层环境中被执行,否则该块内的代码不会运行。
将尽可能少的语句放在下面的if__name___=='__main__'块中可以提高代码的清晰度和正确性。
最常见的,一个名为main的函数封装了程序的主要行为:
#echo.py
importshlex
importsys
defecho(phrase:str)->None:
"""Adummywrapperaroundprint."""
#fordemonstrationpurposes,youcanimaginethatthereissome
#valuableandreusablelogicinsidethisfunction
print(phrase)
defmain()->int:
"""Echotheinputargumentstostandardoutput"""
phrase=shlex.join(sys.argv)
echo(phrase)
return0
if__name__=='__main__':
sys.exit(main())#nextsectionexplainstheuseofsys.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(如果你的函数没有返回语句,则隐含返回)。
通过主动遵循这一惯例,我们的模块在直接运行时(即python3echo.py)会有相同的行为,如果我们以后把它打包成可用pip安装的包中的控制台脚本入口,它也会有相同的行为。
特别的是,要小心从你的main函数中返回字符串。
sys.exit()将把一个字符串参数解释为失败信息,所以你的程序将有一个1的退出代码,表示失败。
并且这个字符串将被写入sys.stderr。
前面的echo.py例子举例说明了使用sys.exit(main())的约定。
也參考
Python打包用户指南包含了一系列关于如何用现代工具分发和安装Python包的教程和参考资料。
Python包中的__main__.py¶
如果你不熟悉Python包,请参阅本教程的套件(Package)一节。
最常见的是,__main__.py文件被用来为一个包提供命令行接口。
假设有下面这个虚构的包,"bandclass":
bandclass
├──__init__.py
├──__main__.py
└──student.py
当使用-m标志从命令行直接调用软件包本身时,将执行__main__.py。
比如说。
$python3-mbandclass
这个命令将导致__main__.py的运行。
你如何利用这一机制将取决于你所编写的软件包的性质,但在这个假设的案例中,允许教师搜索学生可能是有意义的:
#bandclass/__main__.py
importsys
from.studentimportsearch_students
student_name=sys.argv[2]iflen(sys.argv)>=2else''
print(f'Foundstudent:{search_students(student_name)}')
注意,from.studentimportsearch_students是一个相对导入的例子。
这种导入方式可以在引用一个包内的模块时使用。
更多细节,请参见教程模組(Module)中的套件內引用一节。
常见用法¶
__main__.py的内容通常不是用if__name__=='__main__'区块围起来的。
相反,这些文件保持简短,功能从其他模块执行。
那些其他模块可以很容易地进行单元测试,并且可以适当地重复使用。
如果使用,一个if__name__=='__main__'区块仍然会像预期的那样对包内的__main__.py文件起作用,因为如果导入,它的__name__属性将包括包的路径:
>>>importasyncio.__main__
>>>asyncio.__main__.__name__
'asyncio.__main__'
但这对.zip文件的根目录中的__main__.py文件不起作用。
因此,为了保持一致性,像下面提到的venv这样的最小__main__.py是首选。
也參考
参见venv以了解标准库中最小__main__.py的软件包示例。
它不包含一个if__name__=='__main__'块。
你可以用python3-mvenv[directory]调用它。
参见runpy以了解更多关于-m标志对解释器可执行包的细节。
参见zipapp了解如何运行打包成.zip文件的应用程序。
在这种情况下,Python会在归档文件的根目录下寻找一个__main__.py文件。
import__main__¶
不管Python程序是用哪个模块启动的,在同一程序中运行的其他模块可以通过导入__main__模块来导入顶级环境的范围(namespace)。
这并不是导入一个__main__.py文件,而是导入使用特殊名称'__main__'的哪个模块。
下面是一个使用__main__命名空间的模块的例子:
#namely.py
import__main__
defdid_user_define_their_name():
return'my_name'indir(__main__)
defprint_user_name():
ifnotdid_user_define_their_name():
raiseValueError('Definethevariable`my_name`!')
if'__file__'indir(__main__):
print(__main__.my_name,"foundinfile",__main__.__file__)
else:
print(__main__.my_name)
该模块的用法示例如下:
#start.py
importsys
fromnamelyimportprint_user_name
#my_name="Dinsdale"
defmain():
try:
print_user_name()
exceptValueErrorasve:
returnstr(ve)
if__name__=="__main__":
sys.exit(main())
现在,如果我们启动我们的程序,结果会是这样的:
$python3start.py
Definethevariable`my_name`!
该程序的退出代码为1,表明有错误。
取消对my_name="Dinsdale"这一行的注释,就可以修复程序,现在它的退出状态代码为0,表示成功。
$python3start.py
Dinsdalefoundinfile/path/to/start.py
请注意,导入__main__不会导致无意中运行旨在用于脚本的顶层代码的问题,这些代码被放在模块start的if__name__=="__main__"块中。
为什么这样做?
Python解释器启动时会在sys.modules中插入一个空的__main__模块,并通过运行顶层代码来填充它。
在我们的例子中这就是start模块,它逐行运行并导入namely。
反过来,namely会导入__main__(这其实是start)。
这就是一个导入循环!幸运的是,由于部分填充的__main__模块存在于sys.modules中,Python会将其传递给namely。
请参阅导入系统参考资料中有关__main__的特别考量来了解其中的详情。
PythonREPL是另一个"顶层环境"的例子,所以在REPL中定义的任何东西都成为__main__范围的一部分:
>>>importnamely
>>>namely.did_user_define_their_name()
False
>>>namely.print_user_name()
Traceback(mostrecentcalllast):
...
ValueError:Definethevariable`my_name`!
>>>my_name='Jabberwocky'
>>>namely.did_user_define_their_name()
True
>>>namely.print_user_name()
Jabberwocky
注意,在这种情况下,__main__范围不包含__file__属性,因为它是交互式的。
__main__范围用于pdb和rlcompleter的实现。
目录
__main__---最高层级代码环境
__name__=='__main__'
什么是“最高层级代码环境”?
常见用法
打包考量
Python包中的__main__.py
常见用法
import__main__
上個主題
builtins---內建物件
下個主題
warnings——警告信息的控制
此頁面
回報錯誤
顯示原始碼
瀏覽
索引
模組|
下一頁|
上一頁|
Python»
3.10.7Documentation»
Python標準函式庫(StandardLibrary)»
Python运行时服务»
__main__---最高层级代码环境
|
延伸文章資訊
- 1__main__ — Top-level code environment — Python 3.10 ...
__main__ is the name of the environment where top-level code is run. “Top-level code” is the firs...
- 2簡易理解python中的if __name__ == 'main' 的作用和原理
從學到python以來,常常看到很多函式(function)中出現以下的語句 if __name__ == '__main__': 雖然一直知道他是用來做甚麼的,但是卻不太能理解他的 ...
- 3Python中__main__和__init__ 的解析 - 知乎专栏
正确题目应该是Python中if __name__ == '__main__',__init__和self 的解析。 ... 如果没有在__init__中初始化对应的实例变量的话,导致后续引用实...
- 4What is __init__ == “__main__” in Python - Medium
A module can define functions, classes and variables. So when the interpreter runs a module, the ...
- 5__main__ --- 最高层级代码环境— Python 3.10.7 說明文件
在Python 中,特殊名称 __main__ 被用于两个重要的构造: 程序的最高层级环境的名称,可以 ... bandclass ├── __init__.py ├── __main__.py...