什么是__main__.py?

时间:2010-10-28 12:28:21

标签: python

__main__.py文件的内容是什么,我应该在其中放入什么样的代码,何时应该有?

6 个答案:

答案 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语句将引发错误,而不是无提示地运行错误的模块。