什么是__main__.py?

Mon*_*lik 287 python

__main__.py应该放入什么样的代码,什么样的代码,什么时候应该有?

Ned*_*der 287

通常,通过在命令行上命名.py文件来运行Python程序:

$ python my_program.py
Run Code Online (Sandbox Code Playgroud)

您还可以创建一个充满代码的目录或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
Run Code Online (Sandbox Code Playgroud)

您必须自己决定您的应用程序是否可以从这样执行中受益.


请注意,__main__ 模块通常不是来自__main__.py文件.它可以,但通常不会.运行类似脚本时python my_program.py,脚本将作为__main__模块而不是my_program模块运行.对于python -m my_module以其他方式运行的模块,也会发生这种情况.

如果您__main__在错误消息中看到该名称,那并不一定意味着您应该查找__main__.py文件.

  • 我发现`python -m program_dir`和`python program_dir`有点不同:后者永远不会在目录中运行`__init __.py`(如果有的话). (16认同)
  • @brk:现在似乎并非如此。我刚刚尝试了python3 program_dir,它运行了__init__.py。 (3认同)
  • @mk12我刚刚尝试过,我可以确认@brk的发现:`python3 dir`运行`__main__.py`,但不运行`__init__.py`,而`python3 -m dir`运行两者。 (3认同)
  • @mk12可能你在`__main__.py`中有一些代码触发了`__init__.py`的导入 (2认同)
  • 我将 `__main__.py` 放在项目的根目录中,这样开发人员就可以运行 `python .` 瞧! (2认同)

Aar*_*all 87

__main__.py文件是什么?

在创建Python模块时,通常使模块在main作为程序的入口点运行时执行某些功能(通常包含在函数中).这通常通过放置在大多数Python文件底部的以下常用习惯来完成:

if __name__ == '__main__':
    # execute only if run as the entry point into the program
    main()
Run Code Online (Sandbox Code Playgroud)

你可以用Python获得相同的语义__main__.py.这是一个linux shell提示符,$如果你在Windows上没有Bash(或另一个Posix shell),只需在demo/__<init/main>__.pyEOF 上创建这些文件:

$ 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
Run Code Online (Sandbox Code Playgroud)

(在Posix/Bash shell中,您可以通过在每个cat命令的末尾输入Ctrl-D(文件结尾字符)来执行上述操作而不使用EOFs和结束<< EOFs

现在:

$ python demo
demo/__main__.py executed
demo/__init__.py executed
main executed
Run Code Online (Sandbox Code Playgroud)

您可以从文档中获得此信息.该文件说:

EOF - 顶级脚本环境

__main__是顶级代码执行的范围的名称.模块的'__main__'设置等于__name__从标准输入,脚本或交互式提示中读取的内容.

模块可以通过检查它自己来检测它是否在主作用域中运行'__main__',这允许在模块作为脚本运行时有条件地执行模块中的常用习惯用法,或者__name__在导入时使用但不是

if __name__ == '__main__':
      # execute only if run as a script
      main()
Run Code Online (Sandbox Code Playgroud)

对于包,通过包含一个python -m模块可以实现相同的效果, 模块的内容将在运行模块时执行__main__.py.

拉链

您也可以将它打包到一个文件中并从命令行运行它 - 但请注意,压缩包不能执行子包或子模块作为入口点:

$ python -m zipfile -c demo.zip demo/*
$ python demo.zip
demo/__main__.py executed
demo/__init__.py executed
main() executed
Run Code Online (Sandbox Code Playgroud)

  • 你会在 `__main__.py` 中使用 `if __name__ == '__main__'` 吗?或者说是没有必要的? (3认同)
  • 我相信这是多余的。 (3认同)

Blu*_*ers 28

__main__.py用于zip文件中的python程序.该__main__.py文件将在zip文件运行时执行.例如,如果zip文件是这样的:

test.zip
     __main__.py
Run Code Online (Sandbox Code Playgroud)

和的内容__main__.py

import sys
print "hello %s" % sys.argv[1]
Run Code Online (Sandbox Code Playgroud)

那么如果我们要跑,python test.zip world我们就会hello world离开.

因此,__main__.py当在zip文件上调用python时,文件会运行.


ana*_*nik 20

创建__main__.pyyourpackage使其可执行文件:

$ python -m yourpackage
Run Code Online (Sandbox Code Playgroud)

  • 如果只有程序可以作为模块访问,则“-m”才有效,否则您可以使用“python &lt;yourpackage&gt;”注意:没有“-m”选项 (2认同)
  • @BenyaminJafari 这是危险的建议。使用或不使用“-m”开关运行之间有一个非常重要的区别。我在下面添加了一个答案来澄清这一点,以便任何未来的读者想知道其中的区别。 (2认同)

Tas*_*nou 20

这里的一些答案暗示,给定一个__init__.py包含__main__.py文件的“包”目录(带有或不带有显式文件),使用-m开关运行该目录与不使用开关没有区别。

大不同的是,没有-m开关,该“包”的目录首先被添加到路径(即sys.path中),然后将文件被运行正常,无包语义

-m开关,包语义(包括相对进口)很荣幸,和包目录本身是永远不会添加到系统路径

这是一个非常重要的区别,无论是在相对导入是否有效方面,更重要的是在规定在系统模块意外遮蔽的情况下将导入什么方面。


例子:

考虑一个PkgTest具有以下结构的目录

:~/PkgTest$ tree
.
??? pkgname
?   ??? __main__.py
?   ??? secondtest.py
?   ??? testmodule.py
??? testmodule.py
Run Code Online (Sandbox Code Playgroud)

其中__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()
Run Code Online (Sandbox Code Playgroud)

(其他文件的定义类似,打印输出类似)。

如果你在没有-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
Run Code Online (Sandbox Code Playgroud)

而使用 -m 开关,你会得到你(希望)所期望的:

:~/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
Run Code Online (Sandbox Code Playgroud)

注意:老实说,-m应该避免空跑。事实上,我会更进一步说我会executable packages以这样的方式创建任何东西,除非通过-m交换机运行,否则它们会失败。

换句话说,假设所有其他导入都代表系统模块,我只会通过“相对导入”显式从“包内”模块导入。如果有人试图在没有-m开关的情况下运行您的包,相关的导入语句将抛出错误,而不是静默运行错误的模块。

  • 对相对导入的影响的解释非常有帮助,谢谢。 (5认同)
  • 无耻插件:如果有人感兴趣,[这是我制作的一个很好的模板](https://github.com/tpapastylianou/executable-python-package-template),用于创建此类独立的可执行 python 包。:) (2认同)

Woo*_*ble 14

如果您的脚本是目录或ZIP文件而不是单个python文件,__main__.py则在将"脚本"作为参数传递给python解释器时将执行.