在 Python 中定义 Main 函数 (一)

许多编程语言都有一个特殊的函数,当操作系统开始运行程序时会自动执行该函数。这个函数通常被命名为 main(),并且依据语言标准具有特定的返回类型和参数。另一方面,Python 解释器从文件顶部开始执行脚本,并且没有自动执行的特殊函数。
尽管如此,为程序的执行定义一个起始点有助于理解程序是如何运行的。Python 程序员提出了几种方式对此进行实现。
本文将了解以下内容:

  • 什么是特殊的 __name__ 变量以及 Python 中如何定义它

  • 为什么要在 Python 中使用 main() 函数

  • 在 Python 中定义 main() 函数有哪些约定

  • main() 函数中应该包含哪些代码的最佳实践
    Python 中的基本 main() 函数
    一些 Python 脚本中,包含一个函数定义和一个条件语句,如下所示:

def  main():
	  print("hello world")

if __name__ == "__main__":
   main()

此代码中,包含一个 main() 函数,在程序执行时打印 Hello World!。此外,还包含一个条件(或 if)语句,用于检查 __name__ 的值并将其与字符串 "main" 进行比较。当 if 语句为 True 时,Python 解释器将执行 main() 函数。更多关于 Python 条件语句的信息可以由此获得。

这种代码模式在 Python 文件中非常常见,它将作为脚本执行并导入另一个模块。为了帮助理解这段代码的执行方式,首先需要了解 Python 解释器如何根据代码的执行方式设置 __name__。

Python 中的执行模式

Python 解释器执行代码有两种方式:

  1. 通过命令行方式执行 Python 脚本。

  2. 将代码从一个文件导入另一个文件或者解释器。

更多内容可参考如何运行 Python 脚本。无论采用哪种方式,Python 都会定义一个名为 __name__ 的特殊变量,该变量包含一个字符串,其值取决于代码的使用方式。

本文将如下示例文件保存为 execution_methods.py,以探索代码如何根据上下文改变行为:
在 Python 中定义 Main 函数 (一)
在此文件中,定义了三个对 print()函数的调用。前两个打印一些介绍性短语。第三个 print() 会先打印短语 The value name is,之后将使用 Python 内置的 repr() 函数打印出 __name__ 变量。

在 Python 中,repr()函数将对象转化为供解释器读取的形式。上述示例通过使用 repr() 函数来强调 __name__ 的值为字符串。更多关于 repr() 的内容可参考 Python 文档。

在本文中,您将随处可见文件 (file),模块(module) 和脚本 (script) 这三个字眼。实际上,三者之间并无太大的差别。不过,在强调代码目的时,还是存在细微的差异:

  1. 文件:通常,Python 文件是包含代码的任何文件。大多数 Python 文件的扩展名为.py。

  2. 脚本:Python 脚本是基于命令行执行以完成某项任务的一类文件。

  3. 模块:Python 模块是从另一个模块、脚本或解释器中导入的文件。更多关于 Python 模块的内容可参考 Python 文档。

“如何运行 Python 脚本”一文也讨论了三者的差别。

基于命令行执行

在这类方法中,Python 脚本将通过命令行来执行。

执行脚本时,无法与 Python 解释器正在执行的代码交互。关于如何通过命令行执行代码的详细信息对本文而言并不重要,但您可以通过展开下框阅读更多有关 Windows,Linux 和 macOS 之间命令行差异的内容。

命令行环境

不同的操作系统在使用命令行执行代码时存在细微的差异。

在 Linux 和 macOS 中,通常使用如下命令:
在 Python 中定义 Main 函数 (一)
美元符号 ($) 之前的内容可能有所不同,具体取决于您的用户名和计算机名称。您键入的命令位于 $ 之后。在 Linux 或 macOS 上,Python3 的可执行文件名为 python3,因此可以通过输入 python3 script_name.py 来运行 python 脚本。

在 Windows 上,命令提示符通常如下所示:
在 Python 中定义 Main 函数 (一)
根据您的用户名,> 之前的内容可能会有所不同,您输入的命令位于 > 之后。在 Windows 上,Python3 的可执行文件通常为 python。因此可以通过输入 python script_name.py 来运行 python 脚本。

无论哪种操作系统,本文的 Python 脚本的输出结果都是相同的。因此本文以 Linux 和 macOS 为例。

使用命令行执行 execution_methods.py,如下所示:
在 Python 中定义 Main 函数 (一)

在这个示例中,__name__ 具有值’main‘,其中引号 (’) 表明该值为字符串类型。

请记住,在 Python 中,使用单引号 (’) 和双引号 (") 定义的字符串没有区别。更多关于字符串的内容请参考 Python 的基本数据类型。

如果在脚本中包含 "shebang 行" 并直接执行它 (./execution_methods.py),或者使用 IPython 或 Jupyter Notebook 的 %run,将会获取相同的结果。

您还可以通过向命令行添加 -m 参数的方法实现以模块的方式执行。通常情况下,推荐如下方式 pip: python3 -m pip install package_name。

添加 -m 参数将会运行包中 __main__.py 的代码。更多关于 __main__.py 文件的内容可参考如何将开源 Python 包发布到 PyPI 中。

在三种情况中,__name__ 都具有相同的值:字符串’main’。

技术细节:Python 文档中具体定义了 __name__ 何时取值为’main’。

当通过标准输入,脚本或者交互提示中读取数据时,模块的 __name__ 将取值为’main’。(来源)

name__ 与 __doc,__package__ 和其他属性一起存储在模块的全局命名空间。更多关于属性的信息可参考 Python 数据模型文档,特别是关于模块和包的信息,请参阅 Python Import 文档。

导入模块或解释器

接下来是 Python 解释器执行代码的第二种方式:导入。在开发模块或脚本时,可以使用 import 关键字导入他人已经构建的模块。

在导入过程中,Python 执行指定模块中定义的语句(但仅在第一次导入模块时)。要演示导入 execution_methods.py 文件的结果,需要启动 Python 解释器,然后导入 execution_methods.py 文件:

在 Python 中定义 Main 函数 (一)

在此代码输出中,Python 解释器执行了三次 print() 函数调用。前两行由于没有变量,在输出方面与在命令行上作为脚本执行时完全相同。但是第三个输出存在差异。

当 Python 解释器导入代码时,__name__ 的值与要导入的模块的名称相同。您可以通过第三行的输出了解这一点。__name__ 的值为’execution_methods’,是 Python 导入的.py 文件。

注意如果您在没有退出 Python 时再次导入模块,将不会有输出。

注意:更多关于导入在 Python 中如何工作的内容请参考官方文档和 Python 中的绝对和相对导入。