__main__.py
文件的内容是什么,我应该在其中放入什么样的代码,何时应该有?
答案 0 :(得分:266)
通常,通过在命令行上命名.py文件来运行Python程序:
$ python my_program.py
您还可以创建一个充满代码的目录或zipfile,并包含__main__.py
。然后,您只需在命令行上命名目录或zipfile,它就会自动执行__main__.py
:
$ python my_program_dir
$ python my_program.zip
# Or, if the program is accessible as a module
$ python -m my_program
您必须自己决定您的应用程序是否可以从这样执行中受益。
请注意,__main__
模块通常不是来自__main__.py
文件。它可以,但通常不会。运行python my_program.py
之类的脚本时,脚本将作为__main__
模块而不是my_program
模块运行。对于以python -m my_module
运行的模块或其他几种方式,也会发生这种情况。
如果您在错误消息中看到名称__main__
,则这并不一定意味着您应该查找__main__.py
文件。
答案 1 :(得分:70)
__main__.py
文件是什么?
创建Python模块时,通常使模块在作为程序的入口点运行时执行某些功能(通常包含在main
函数中)。这通常通过放置在大多数Python文件底部的以下常用习惯来完成:
if __name__ == '__main__':
# execute only if run as the entry point into the program
main()
对于包含__main__.py
的Python包,您可以获得相同的语义。这是一个linux shell提示符$
,如果您在Windows上没有Bash(或其他Posix shell),只需在demo/__<init/main>__.py
创建这些文件,其中的内容介于EOF
之间S:
$ mkdir demo
$ cat > demo/__init__.py << EOF
print('demo/__init__.py executed')
def main():
print('main executed')
EOF
$ cat > demo/__main__.py << EOF
print('demo/__main__.py executed')
from __init__ import main
main()
EOF
(在Posix / Bash shell中,您可以输入 Ctrl + D << EOF和结束EOF
的情况下执行上述操作>,每个cat命令末尾的文件结束字符)
现在:
$ python demo
demo/__main__.py executed
demo/__init__.py executed
main executed
您可以从文档中获取此信息。 documentation说:
__main__
- 顶级脚本环境
'__main__'
是顶级代码执行的范围的名称。 从标准读取时,模块的__name__
设置为'__main__'
输入,脚本或交互式提示。模块可以发现它是否在主范围内运行 通过检查自己的
__name__
,它允许一个常见的习语 当它作为脚本运行时,有条件地执行模块中的代码 使用python -m
但不是导入时:if __name__ == '__main__': # execute only if run as a script main()
对于包装,通过包括a可以实现相同的效果
__main__.py
模块,当模块与-m
一起运行时,将执行其内容。
你也可以将它打包成一个文件并从命令行运行它 - 但请注意,压缩包不能作为入口点执行子包或子模块:
$ python -m zipfile -c demo.zip demo/*
$ python demo.zip
demo/__main__.py executed
demo/__init__.py executed
main() executed
答案 2 :(得分:24)
__main__.py
用于zip文件中的python程序。运行时压缩文件将执行__main__.py
文件。例如,如果zip文件是这样的:
test.zip
__main__.py
并且__main__.py
的内容是
import sys
print "hello %s" % sys.argv[1]
然后,如果我们要运行python test.zip world
,我们就会hello world
出来。
因此在zip文件上调用python时运行__main__.py
文件。
答案 3 :(得分:17)
您在__main__.py
中创建yourpackage
以使其可执行为:
$ python -m yourpackage
答案 4 :(得分:14)
如果您的脚本是目录或ZIP文件而不是单个python文件,则当“脚本”作为参数传递给python解释器时,将执行__main__.py
。
答案 5 :(得分:4)
此处的某些答案表示,给定包含一个__init__.py
文件的“ package”目录(没有__main__.py
文件的目录),使用{{ 1}}是否切换。
最大的区别在于,没有 -m
开关,“ package”目录首先添加到路径(即sys.path),并且然后文件将正常运行,没有包语义。
使用和 -m
开关,将尊重软件包的语义(包括相对导入),并且软件包目录本身不会添加到系统路径。
这是一个非常重要的区别,无论是相对导入是否有效,更重要的是,在确定在系统模块意外遮盖的情况下导入什么。
示例:
考虑具有以下结构的名为-m
的目录
PkgTest
其中:~/PkgTest$ tree
.
├── pkgname
│ ├── __main__.py
│ ├── secondtest.py
│ └── testmodule.py
└── testmodule.py
文件具有以下内容:
__main__.py
(其他文件的定义与打印输出类似)。
如果您在没有:~/PkgTest$ cat pkgname/__main__.py
import os
print( "Hello from pkgname.__main__.py. I am the file", os.path.abspath( __file__ ) )
print( "I am being accessed from", os.path.abspath( os.curdir ) )
from testmodule import main as firstmain; firstmain()
from .secondtest import main as secondmain; secondmain()
开关的情况下运行此程序,则将获得此结果。请注意,相对导入失败,但更重要的是,请注意选择了错误的测试模块(即相对于工作目录):
-m
使用-m开关,您可以(希望)得到期望的结果:
:~/PkgTest$ python3 pkgname
Hello from pkgname.__main__.py. I am the file ~/PkgTest/pkgname/__main__.py
I am being accessed from ~/PkgTest
Hello from testmodule.py. I am the file ~/PkgTest/pkgname/testmodule.py
I am being accessed from ~/PkgTest
Traceback (most recent call last):
File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "pkgname/__main__.py", line 10, in <module>
from .secondtest import main as secondmain
ImportError: attempted relative import with no known parent package
注意:以我的诚实观点,应避免在没有:~/PkgTest$ python3 -m pkgname
Hello from pkgname.__main__.py. I am the file ~/PkgTest/pkgname/__main__.py
I am being accessed from ~/PkgTest
Hello from testmodule.py. I am the file ~/PkgTest/testmodule.py
I am being accessed from ~/PkgTest
Hello from secondtest.py. I am the file ~/PkgTest/pkgname/secondtest.py
I am being accessed from ~/PkgTest
的情况下运行。实际上,我会更进一步地说,我将以某种方式创建任何-m
,除非通过executable packages
开关运行它们,否则它们将失败。
换句话说,假设所有其他导入都代表系统模块,我将仅通过“相对导入”从“封装中”模块显式导入。如果有人尝试在没有-m
开关的情况下运行您的软件包,则相对的import语句将引发错误,而不是无提示地运行错误的模块。