跳至主要内容

if __name__ == "__main__" Python:完整解读

Python 中的 if __name__ == "__main__" 代码块可让您定义仅在文件作为脚本直接执行时运行、而在被作为模块导入到其他脚本时不运行的代码。
· 8分钟 阅读

使用 AI 探索

以 if __name__ == "__main__" 开头的条件代码块在 Python 代码中很常见。这一行看起来有些晦涩,许多初学者在并不了解其作用或是否应当使用的情况下就直接使用它。来自其他语言的程序员也常常误解并过度使用这一惯用法。

本教程将深入讲解 Python 的 if__name__ == "__main__" 惯用法的含义,并探讨如何以及何时使用它。

理解 __name__ 和 "__main__"

惯用法 if __name__ == "__main__" 是一个 if 语句,用于判断是否相等。

等号运算符 == 左侧的第一个操作数是 属性 __name__。以双下划线开头和结尾的 Python 名称是特殊标识符。每个模块都有一个 __name__ 属性。Python 会将该变量设置为模块名,导入系统据此唯一标识每个模块。

不过,如果模块处于顶层代码环境,也就是作为程序的入口模块,Python 会将 __name__ 属性设置为字符串 "__main__"。

我们来看一些示例。先创建一个名为 exploring_name_main.py 的脚本:

# exploring_name_main.py
import random
print(__name__)
print(random.__name__)

可以在终端中用以下命令直接运行该脚本:

$ python exploring_name_main.py
__main__
random

脚本 exploring_name_main.py 位于顶层代码环境,因为它是程序的入口点。因此,__name__ 变量被设置为字符串 "__main__"。

然而,random 模块是被导入的,不在顶层代码环境中。它的 __name__ 属性被设置为模块自身的名称。

接下来,我们创建一个新脚本 more_exploration.py,它会导入第一个脚本:

# more_exploration.py
import exploring_name_main

在终端中用以下命令运行该脚本:

$ python more_exploration.py
exploring_name_main
random

模块在被导入时会执行其中的代码。因此,当运行 more_exploration.py 时,会显示 exploring_name_main.py 中两个 print() 调用的输出。由于 exploring_name_main.py 不再是程序的入口,其 __name__ 属性被设置为脚本名,而不是 "__main__"。

if __name__ == "__main__" 条件代码块

变量 __name__ 可用于判断某个模块是否是程序的主入口。因此,模块可以包含仅在其作为脚本直接运行时才会执行、而在被导入时不会执行的代码。任何只应在脚本被直接运行时执行的代码,都应包含在 if __name__ == "__main__" 条件代码块中:

# exploring_name_main.py
import random
print(__name__)
print(random.__name__)
number = random.randint(1, 10)
if __name__ == "__main__":
    print("This script is in the top-level code environment")
    print(f"The number is {number}")

现在,exploring_name_main.py 中包含了一个 if __name__ == "__main__" 条件代码块。我们来看直接运行脚本时是否会有不同:

$ python exploring_name_main.py
__main__
random
This script is in the top-level code environment
The number is 10

当脚本被直接运行时,变量 __name__ 被设置为字符串 "__main__"。因此,if 语句中的条件判断为 True,Python 会执行 if 块中的代码。

但是,当模块被导入时,__name__ 被设置为模块名,程序不会执行 if 块。回想一下脚本 more_exploration.py 导入了 exploring_name_main:

$  python more_exploration.py
exploring_name_main
random

程序没有调用 exploring_name_main.py 中的 print()。这些调用位于条件代码块中,由于 __name__ 不等于 "__main__",因此不会执行。

使用 Python 的 if __name__ == "__main__" 时的最佳实践与提示

当代码应当仅在文件作为脚本运行而非作为模块导入时,Python 的 if __name__ == "__main__" 惯用法就会派上用场。术语脚本与模块之间的区别只在于文件的使用方式。二者都指以 .py 结尾的文件。

一个常见用例是脚本中包含的变量、函数和类可能会在其他程序中复用。以下是一个名为 shapes.py 的脚本示例:

# shapes.py
import math
def find_area_of_circle(radius):
    return math.pi * radius ** 2
def find_area_of_rectangle(width, height):
    return width * height
if __name__ == "__main__":
    shape = int(input("Enter 1 for circle, 2 for rectangle: "))
    if shape == 1:
        radius = int(input("Enter radius: "))
        print(f"The area of the circle is {find_area_of_circle(radius)}")
    elif shape == 2:
        width = int(input("Enter width: "))
        height = int(input("Enter height: "))
        print(f"The area of the rectangle is {find_area_of_rectangle(width, height)}")
Enter 1 for circle, 2 for rectangle: 2
Enter width: 10
Enter height: 20
The area of the rectangle is 200

如果始终打算将其作为脚本运行,则不需要使用 if __name__ == "__main__" 惯用法。然而,加入该条件语句可以使代码在被作为模块导入时,不会执行 if 块中的语句。再看另一个名为 more_shapes.py 的脚本:

# more_shapes.py
import shapes
radius = 5
print(f"The area of the circle defined in 'more_shapes.py' is: "
      f"{shapes.find_area_of_circle(radius)}")
The area of the circle defined in 'more_shapes.py' is: 78.53981633974483

这个新脚本 more_shapes.py 因为导入了 shapes.py,因此可以使用其中定义的函数。但 shapes.py 中 if __name__ == "__main__" 块里的代码并不会被执行。若 shapes.py 中没有 if 语句,那么在该模块被导入时,所有代码都会被执行。

将用户输入逻辑放在 if __name__ == "__main__" 块中是一个常见做法。这样一来,当文件作为模块被导入时会跳过用户输入,而在作为顶层代码直接执行时则会包含这些输入。

使用 main() 函数

最佳实践是尽量减少放入 if __name__ == "__main__" 代码块中的语句,以提升代码可读性。常见方式是创建一个函数,并在条件块中调用它。该函数通常命名为 main(),但任何函数名都可以:

# shapes.py
import math
def find_area_of_circle(radius):
    return math.pi * radius ** 2
def find_area_of_rectangle(width, height):
    return width * height
def main():
    shape = int(input("Enter 1 for circle, 2 for rectangle: "))
    if shape == 1:
        radius = int(input("Enter radius: "))
        print(f"The area of the circle is {find_area_of_circle(radius)}")
    elif shape == 2:
        width = int(input("Enter width: "))
        height = int(input("Enter height: "))
        print(f"The area of the rectangle is {find_area_of_rectangle(width, height)}")
       
if __name__ == "__main__":
    main()

main() 函数中的代码与早先版本中直接写在 if __name__ == "__main__" 块里的代码相同。

与某些其他编程语言不同,Python 并不要求必须使用 main() 函数作为程序的主入口。因此,是否使用 main() 和 if __name__ == "__main__" 惯用法是可选的,只有当代码既希望作为独立脚本运行、又希望作为模块使用时才需要。

Python 的 if __name__ == "__main__" 的另一个常见用例是 在脚本中包含测试。当脚本被直接执行时会运行测试,而当从其他模块导入时则不会运行。不过,这种方法适用于简单场景,更好的做法是将测试放在专门的测试模块中。

结论

Python 的 if __name__ == "__main__" 适用于编写仅在脚本被直接运行时执行、而在被导入时不执行的代码。当模块被导入时,Python 解释器将 __name__ 变量设置为模块名;当模块是程序的主入口时,则设置为字符串 "__main__"。

与某些其他编程语言不同,main() 函数和 if __name__ == "__main__" 惯用法并非运行 Python 代码的必需条件,但它是程序员在需要时可以使用的工具。

Stephen Gruppetta

作者

Stephen Gruppetta

我在马耳他大学完成了本科阶段的物理与数学学习。随后前往伦敦,并在帝国理工学院取得物理学博士学位,研究用于成像人类视网膜的新型光学技术。现在,我专注于撰写与传播 Python 相关内容,并教授 Python。

主题