2023-09-05 08:00:00

什么是__main__.py?

__main__.py文件是干什么用的,我应该把什么样的代码放进去,什么时候我应该有一个?


当前回答

__main__.py文件是干什么用的?

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

if __name__ == '__main__':
    # execute only if run as the entry point into the program
    main()

你可以通过__main__.py获得Python包的相同语义,它可能具有以下结构:

.
└── demo
    ├── __init__.py
    └── __main__.py

要查看这一点,请将以下内容粘贴到Python 3 shell中:

from pathlib import Path

demo = Path.cwd() / 'demo'
demo.mkdir()

(demo / '__init__.py').write_text("""
print('demo/__init__.py executed')

def main():
    print('main() executed')
""")

(demo / '__main__.py').write_text("""
print('demo/__main__.py executed')

from demo import main

main()
""")

我们可以将demo视为一个包,并实际导入它,它会执行__init__.py中的顶层代码(但不是主函数):

>>> import demo
demo/__init__.py executed

当我们使用包作为程序的入口点时,我们在__main__.py中执行代码,它首先导入__init__.py:

$ python -m demo
demo/__init__.py executed
demo/__main__.py executed
main() executed

您可以从文档中得到这一点。文件说:

__main__ — Top-level script environment '__main__' is the name of the scope in which top-level code executes. A module’s __name__ is set equal to '__main__' when read from standard input, a script, or from an interactive prompt. A module can discover whether or not it is running in the main scope by checking its own __name__, which allows a common idiom for conditionally executing code in a module when it is run as a script or with python -m but not when it is imported: if __name__ == '__main__': # execute only if run as a script main() For a package, the same effect can be achieved by including a __main__.py module, the contents of which will be executed when the module is run with -m.

压缩

你也可以将这个目录,包括__main__.py,压缩成一个文件,然后像这样从命令行运行它——但请注意,压缩后的包不能作为入口点执行子包或子模块:

from pathlib import Path

demo = Path.cwd() / 'demo2'
demo.mkdir()

(demo / '__init__.py').write_text("""
print('demo2/__init__.py executed')

def main():
    print('main() executed')
""")

(demo / '__main__.py').write_text("""
print('demo2/__main__.py executed')

from __init__ import main

main()
""")

注意细微的变化——我们从__init__而不是demo2导入main——这个压缩目录不被视为一个包,而是一个脚本目录。所以它必须在不带-m标志的情况下使用。

与问题特别相关的是——zipapp会导致压缩目录默认执行__main__.py——并且它会在__init__.py之前先执行:

$ python -m zipapp demo2 -o demo2zip
$ python demo2zip
demo2/__main__.py executed
demo2/__init__.py executed
main() executed

请再次注意,这个压缩目录不是一个包-您也不能导入它。

其他回答

__main__.py文件是干什么用的?

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

if __name__ == '__main__':
    # execute only if run as the entry point into the program
    main()

你可以通过__main__.py获得Python包的相同语义,它可能具有以下结构:

.
└── demo
    ├── __init__.py
    └── __main__.py

要查看这一点,请将以下内容粘贴到Python 3 shell中:

from pathlib import Path

demo = Path.cwd() / 'demo'
demo.mkdir()

(demo / '__init__.py').write_text("""
print('demo/__init__.py executed')

def main():
    print('main() executed')
""")

(demo / '__main__.py').write_text("""
print('demo/__main__.py executed')

from demo import main

main()
""")

我们可以将demo视为一个包,并实际导入它,它会执行__init__.py中的顶层代码(但不是主函数):

>>> import demo
demo/__init__.py executed

当我们使用包作为程序的入口点时,我们在__main__.py中执行代码,它首先导入__init__.py:

$ python -m demo
demo/__init__.py executed
demo/__main__.py executed
main() executed

您可以从文档中得到这一点。文件说:

__main__ — Top-level script environment '__main__' is the name of the scope in which top-level code executes. A module’s __name__ is set equal to '__main__' when read from standard input, a script, or from an interactive prompt. A module can discover whether or not it is running in the main scope by checking its own __name__, which allows a common idiom for conditionally executing code in a module when it is run as a script or with python -m but not when it is imported: if __name__ == '__main__': # execute only if run as a script main() For a package, the same effect can be achieved by including a __main__.py module, the contents of which will be executed when the module is run with -m.

压缩

你也可以将这个目录,包括__main__.py,压缩成一个文件,然后像这样从命令行运行它——但请注意,压缩后的包不能作为入口点执行子包或子模块:

from pathlib import Path

demo = Path.cwd() / 'demo2'
demo.mkdir()

(demo / '__init__.py').write_text("""
print('demo2/__init__.py executed')

def main():
    print('main() executed')
""")

(demo / '__main__.py').write_text("""
print('demo2/__main__.py executed')

from __init__ import main

main()
""")

注意细微的变化——我们从__init__而不是demo2导入main——这个压缩目录不被视为一个包,而是一个脚本目录。所以它必须在不带-m标志的情况下使用。

与问题特别相关的是——zipapp会导致压缩目录默认执行__main__.py——并且它会在__init__.py之前先执行:

$ python -m zipapp demo2 -o demo2zip
$ python demo2zip
demo2/__main__.py executed
demo2/__init__.py executed
main() executed

请再次注意,这个压缩目录不是一个包-您也不能导入它。

如果你的脚本是一个目录或ZIP文件,而不是一个单一的python文件,当“script”作为参数传递给python解释器时,__main__.py将被执行。

你在你的包中创建__main__.py,使其可执行:

$ python -m yourpackage

__main__.py用于zip文件中的python程序。当zip文件运行时,__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文件将运行。

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

$ python my_program.py

你也可以创建一个充满代码的目录或zip文件,并包含__main__.py。然后你可以简单地在命令行上命名目录或zip文件,它会自动执行__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文件。