如果 __name__ == "__main__" 是什么意思?

8132
这段代码的作用是什么?为什么要使用 if 语句?
if __name__ == "__main__":
    print("Hello, World!")

如果您要关闭一个问题,而有人应该使用这个习惯用语却没有使用,请考虑将其作为为什么在导入时Python运行我的模块,我该如何停止?的重复项进行关闭。对于那些只是没有调用任何函数或错误地期望使用名为main的函数作为自动入口点的问题,请使用当我启动Python脚本时,为什么不运行main()函数?脚本从哪里开始运行?


38
“__main__”是Python中的一个特殊变量,表示当前执行的模块是主程序。当一个Python程序被直接运行时,它的“__name__”变量被设置为“__main__”,而当它被作为一个模块导入到其他程序中时,“__name__”变量会被设置为该模块的名称。更多信息可以查看文档:https://docs.python.org/3/reference/toplevel_components.html#complete-python-programs 和 https://docs.python.org/3/reference/import.html?highlight=__name__#__name__ - Konstantin Burlachenko
30
有多少人来到这里是因为想要复制粘贴“if name == "main":”呢?:-P - Aaron John Sabu
2
如果您想编写旨在被“导入”但也可以作为独立的shell脚本运行的Python代码,这将非常有用。 由if __name__检查保护的代码仅在作为命令调用时运行,而不是在导入时运行。 如果您想使用交互式Python会话调试Python脚本,这也很有用。 您可以在交互式会话中“导入”通常作为命令运行的代码,然后手动输入代码以您喜欢的方式运行脚本中的函数/类。 - cnamejj
3
对于任何来到这里的人,[7:32] You should put this in all your Python scripts | if __name__ == '__main__': ... by YouTube channel mCoding 提供了一个很好的解释和讨论这个习语的后果。标题可能对于SO来说太过规定,但是解释很好。 - eccentricOrange
46个回答

8770

简短回答

这是一段样板代码,用于保护用户在不打算调用脚本时的意外调用。以下是省略了保护代码的脚本可能出现的常见问题:

  • 如果你在另一个脚本中导入了没有保护代码的脚本(例如:import my_script_without_a_name_eq_main_guard),那么后者将会在导入时使用第二个脚本的命令行参数来触发前者运行。这几乎总是一个错误。

  • 如果你在没有保护代码的脚本中有一个自定义类,并将其保存到pickle文件中,然后在另一个脚本中对其进行反序列化,将会触发对没有保护代码的脚本的导入,其中包含了前面提到的相同问题。

详细回答

为了更好地理解为什么以及如何重要,我们需要退后一步,了解Python如何初始化脚本以及它与模块导入机制的交互方式。

每当Python解释器读取一个源文件时,它会执行两件事:

  • 它设置一些特殊变量,例如__name__,然后

  • 它执行文件中找到的所有代码。

让我们看看它是如何工作的,以及它与你在Python脚本中经常看到的__name__检查有什么关系。

代码示例

让我们使用稍微不同的代码示例来探索导入和脚本的工作方式。假设以下内容位于名为foo.py的文件中。

# Suppose this is foo.py.

print("before import")
import math

print("before function_a")
def function_a():
    print("Function A")

print("before function_b")
def function_b():
    print("Function B {}".format(math.sqrt(100)))

print("before __name__ guard")
if __name__ == '__main__':
    function_a()
    function_b()
print("after __name__ guard")

特殊变量

当Python解释器读取源文件时,它首先定义了一些特殊变量。在这种情况下,我们关心__name__变量。

当您的模块是主程序时

如果您正在运行您的模块(源文件)作为主程序,例如:

python foo.py

解释器将把硬编码的字符串"__main__"赋值给__name__变量,即。
# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__" 

当你的模块被其他模块导入时
另一方面,假设某个其他模块是主程序并且导入了你的模块。这意味着在主程序中或者在主程序导入的其他模块中会有类似这样的语句:
# Suppose this is in some other main program.
import foo

解释器将搜索您的foo.py文件(以及其他几个变体),在执行该模块之前,它将从导入语句中将名称"foo"分配给__name__变量。
# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"

执行模块代码

在设置好特殊变量之后,解释器逐条执行模块中的所有代码。您可能希望在一侧打开另一个窗口,以便可以跟随本说明进行。

始终如此

  1. 它打印字符串"before import"(不包含引号)。

  2. 它加载math模块并将其赋值给名为math的变量。这相当于用以下内容替换import math(请注意,__import__是Python中的低级函数,它接受一个字符串并触发实际的导入):

# Find and load a module given its string name, "math",
# then assign it to a local variable called math.
math = __import__("math")
  1. 它打印字符串 "before function_a"。
  2. 它执行 def 代码块,创建一个函数对象,然后将该函数对象赋值给名为 function_a 的变量。
  3. 它打印字符串 "before function_b"。
  4. 它执行第二个 def 代码块,创建另一个函数对象,然后将其赋值给名为 function_b 的变量。
  5. 它打印字符串 "before __name__ guard"。

只有当你的模块是主程序时

  1. 如果你的模块是主程序,则它会发现 __name__ 确实被设置为 "__main__",并调用这两个函数,打印字符串 "Function A" 和 "Function B 10.0"。

只有当你的模块被其他模块导入时

  1. (相反) 如果你的模块不是主程序,而是被另一个模块导入的,则 __name__ 将会是 "foo" 而不是 "__main__",并且它将跳过 if 语句的内容。

总是

  1. 在两种情况下都会打印字符串 "after __name__ guard"

摘要

总结起来,在这两种情况下将会打印以下内容:

# What gets printed if foo is the main program
before import
before function_a
before function_b
before __name__ guard
Function A
Function B 10.0
after __name__ guard

# What gets printed if foo is imported as a regular module
before import
before function_a
before function_b
before __name__ guard
after __name__ guard

为什么它会这样工作?

你可能自然而然地想知道为什么有人会希望这样做。嗯,有时你希望编写一个 .py 文件,既可以作为模块被其他程序和/或模块使用,又可以作为主程序本身运行。例如:

  • 你的模块是一个库,但你希望它可以以脚本模式运行一些单元测试或演示。

  • 你的模块仅用作主程序,但它具有一些单元测试,并且测试框架通过导入类似于你的脚本的 .py 文件并运行特殊的测试函数来工作。你不希望它在导入模块时尝试运行脚本。

  • 你的模块大部分用作主程序,但同时还为高级用户提供了一个友好的 API。

除了上述例子,Python 中运行脚本只是设置一些特殊变量并导入脚本的模块,这是一种优雅的方式。"运行"脚本只是导入脚本模块的副作用。

思考题

问题:我可以有多个__name__检查块吗?回答:这样做很奇怪,但语言不会阻止你。
假设以下内容在foo2.py中。如果你在命令行上输入python foo2.py会发生什么?为什么?
# Suppose this is foo2.py.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters

def function_a():
    print("a1")
    from foo2 import function_b
    print("a2")
    function_b()
    print("a3")

def function_b():
    print("b")

print("t1")
if __name__ == "__main__":
    print("m1")
    function_a()
    print("m2")
print("t2")
      

现在,弄清楚在删除了__name__检查的情况下,foo3.py中会发生什么:
# Suppose this is foo3.py.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters

def function_a():
    print("a1")
    from foo3 import function_b
    print("a2")
    function_b()
    print("a3")

def function_b():
    print("b")

print("t1")
print("m1")
function_a()
print("m2")
print("t2")

当作脚本使用时,这将会做什么?当作模块导入时呢?
# Suppose this is in foo4.py
__name__ = "__main__"

def bar():
    print("bar")
    
print("before __name__ guard")
if __name__ == "__main__":
    bar()
print("after __name__ guard")

49
如果我在Python脚本中运行subprocess.run('foo_bar.py')会发生什么?我认为foo_bar将以__name__ = '__main__'启动,就像我在命令提示符手动输入foo_bar.py一样。是这种情况吗? 考虑到@MrFooz的回答,这样做不应该有任何问题,可以同时拥有尽可能多的“主”模块。即使更改了__name__值或者独立创建实例(或者通过subprocess相互创建实例),它们之间的交互也应该像平常一样适用于Python。 我有什么遗漏吗? - hajef
40
你说的关于subprocess.run的工作方式是正确的。不过,更好的一种在脚本之间共享代码的方法是创建模块,并让脚本调用共享的模块,而不是像脚本互相调用那样。 subprocess.run 的调试很困难,因为大多数调试器不能跨进程边界跳转,创建和销毁额外的进程可能会增加非微不足道的系统开销等问题。 - Mr Fooz
11
在“思考食品”部分的foo2.py示例中,我有一个疑问。from foo2.py import functionB是什么意思?在我看来,它只是从functionB导入了foo2.py。 - user471651
7
可能会导入你的代码的其中一个模块是 multiprocessing,特别是在 Windows 上需要进行这个测试。 - Yann Vernier
7
非常微小的一点,但我认为Python实际上是通过导入语句来确定导入模块的__name__,而不是通过将文件名中的“.py”去掉。因为Python标识符区分大小写,但文件名可能不一定如此(例如在Windows上),所以文件名中可能没有足够的信息来确定正确的Python模块名。 - Ben
显示剩余17条评论

2175

当您将脚本作为命令传递给Python解释器运行时,

python myscript.py

当代码处于缩进级别为0时,所有代码都会被执行。定义的函数和类是被定义了,但它们的代码不会运行。与其他语言不同的是,没有自动运行的main()函数 - 隐式的main()函数就是顶层的所有代码。

在这种情况下,顶层代码是一个if块。__name__是一个内置变量,它的值为当前模块的名称。但是,如果一个模块直接运行(如上面的myscript.py),那么__name__将被设置为字符串"__main__"。因此,您可以通过测试__name__ == "__main__"来检测脚本是直接运行还是被其他东西导入。

if __name__ == "__main__":
    ...
如果你的脚本被导入到另一个模块中,它的各种函数和类定义将被导入,其顶层代码将被执行,但是由于条件没有满足,上面if语句中的then-body代码不会运行。作为基本示例,请考虑以下两个脚本:
# file one.py
def func():
    print("func() in one.py")

print("top-level in one.py")

if __name__ == "__main__":
    print("one.py is being run directly")
else:
    print("one.py is being imported into another module")
# file two.py
import one

print("top-level in two.py")
one.func()

if __name__ == "__main__":
    print("two.py is being run directly")
else:
    print("two.py is being imported into another module")

现在,如果您作为解释器调用

python one.py

输出结果为

top-level in one.py
one.py is being run directly

如果你运行two.py

python two.py
你得到了什么。
top-level in one.py
one.py is being imported into another module
top-level in two.py
func() in one.py
two.py is being run directly

因此,当模块 one 被加载时,它的 __name__ 等于 "one" 而不是 "__main__"


19
所以,if __name__ == "__main__":基本上检查您是否在运行Python脚本本身,而不是导入它或其他东西? - Merp
@Adam Rosenfield 如果你的脚本被导入到另一个模块中,它的各种函数和类定义将被导入,其顶层代码将被执行...。什么是顶层代码?缩进为零的代码? - John

883
创建以下两个文件:
# a.py

import b
# b.py

print("__name__ equals " + __name__)

if __name__ == '__main__':
    print("if-statement was executed")

现在逐个运行每个文件。


运行 python a.py

$ python a.py
__name__ equals b

当执行 a.py 时,它会导入模块 b。这会使得 b 模块中的所有代码都运行。Python 将在 b 模块中设置 globals()['__name__'] 为模块的名称,即 b


运行 python b.py:

$ python b.py
__name__ equals __main__
if-statement was executed

当仅执行文件b.py时,Python会将该文件中的globals()['__name__']设置为"__main__"。因此,这次if语句的评估结果为True


617

if __name__ == "__main__": 做什么?

简要概述:

  • 全局变量__name__在你程序入口的模块中为 '__main__'。否则它将是你导入该模块的名称。

  • 因此,当模块是程序的入口时,位于if代码块下的代码将会执行。

  • 这允许该模块中的代码作为其他模块可导入的内容,而不会在导入时执行该代码块。


我们为什么需要这个?

开发和测试您的代码

假设您正在编写一个Python脚本,旨在用作模块:

def do_important():
    """This function does something very important"""

您可以通过在底部添加此函数调用来测试该模块:


do_important()

并在命令提示符上运行它,例如:

~$ python important.py

问题

但是,如果您想将这个模块导入到另一个脚本中:

import important

在导入时,会调用do_important函数,因此你可能需要注释掉在底部的do_important()函数调用。
# do_important() # I must remember to uncomment to execute this!

然后你必须记住是否已经注释掉了你的测试函数调用。这种额外的复杂性会使你很可能忘记,使你的开发过程更加麻烦。

更好的方式

__name__变量指向Python解释器当前所在的命名空间。

在导入的模块中,它是该模块的名称。

但是在主模块(或交互式Python会话,即解释器的读取、评估、打印循环或REPL)中,你从中运行所有内容的名称是"__main__"

因此,如果在执行前进行检查:

if __name__ == "__main__":
    do_important()

有了上面的方法,您的代码只会在作为主模块运行时执行(或者故意从另一个脚本中调用它)。

更好的方法

然而,这里有一种更符合Python风格的改进方式。

如果我们想要从模块外部运行此业务流程怎么办?

如果我们将我们想要开发和测试的代码放在这样的一个函数中,然后立即进行'__main__'检查:

Translated Answer:

使用以上方法,您的代码只会在作为主模块运行时执行(或故意从其他脚本中调用它)。

更好的方法

不过,有一种更符合 Python 风格的改进方法。

如果我们想要从模块外部运行这个业务流程,该怎么办呢?

我们可以把我们想要开发和测试的代码放在这个函数里,然后立刻进行 '__main__' 检查:

def main():
    """business logic for when running this module as the primary one!"""
    setup()
    foo = do_important()
    bar = do_even_more_important(foo)
    for baz in bar:
        do_super_important(baz)
    teardown()

# Here's our payoff idiom!
if __name__ == '__main__':
    main()

现在我们有了一个最终函数,它将在我们将模块作为主模块运行时运行。

这将允许将模块及其函数和类导入其他脚本,而不运行main函数,并且还将允许在从不同的'__main__'模块运行时调用模块(及其函数和类)。

import important
important.main()

这个习语也可以在 Python 文档中的 __main__ 模块解释中找到。文本说明:

This module represents the (otherwise anonymous) scope in which the interpreter’s main program executes — commands read either from standard input, from a script file, or from an interactive prompt. It is this environment in which the idiomatic “conditional script” stanza causes a script to run:

if __name__ == '__main__':
    main()

抱歉,我无法确定在名为“更好的方法”的部分提到的方法和在名为“甚至更好的方法”的部分提到的方法之间是否有任何区别。您能指出来吗? - John
@John 我认为没有区别。他使用 更好的方法 来说明我们如何将模块作为脚本运行,而使用 更好的方式 来说明我们如何在其他地方导入模块并仍然运行它。 - BtLutz

178

if __name__ == "__main__" 是当脚本使用类似 python myscript.py 命令从命令行运行时运行的部分。


5
为什么一个只包含print("hello world")的文件名为helloworld.py的文件,可以通过命令python helloworld.py运行,即使没有if __name__ == "__main__" - hi15
5
当你运行python helloworld.py时,它将运行整个脚本文件(无论你是否指定了if __name__ == "__main__")。只有在从另一个脚本导入helloworld.py时才会执行不同的操作。在这种情况下,if __name__ == "__main__"代码块根本不执行。 - Nihal Sangeeth

114

if __name__ == "__main__"的作用是什么?

__name__ 是一个全局变量(在 Python 中,全局实际上是指在模块级别),存在于所有命名空间中。通常它是模块的名称(作为 str 类型)。

然而,这是唯一的特殊情况,在你运行的任何 Python 进程中,就像在 mycode.py 中:

python mycode.py

否则匿名的全局命名空间被赋值为 '__main__' ,其 __name__ 属性也被设置为这个值。

因此,包括最终行

if __name__ == '__main__':
    main()
  • 在您的 mycode.py 脚本末尾,
  • 当它是 Python 进程运行的主要入口模块时,

将导致您脚本中唯一定义的 main 函数运行。

使用此结构的另一个好处是:您还可以将您的代码作为模块导入另一个脚本,然后在程序决定时运行主函数:

import mycode
# ... any amount of other code
mycode.main()

98

这里有很多关于代码机制的不同观点,即“如何”,但对我来说,在理解“为什么”之前,这些都没有意义。这对新手程序员尤其有帮助。

以文件“ab.py”为例:

def a():
    print('A function in ab file');
a()

还有一个名为"xy.py"的文件:

import ab
def main():
    print('main function: this is where the action is')
def x():
    print ('peripheral task: might be useful in other projects')
x()
if __name__ == "__main__":
    main()

当你执行xy.py时,你会import ab。导入语句会立即在导入时运行模块,因此ab的操作会在xy的余下部分之前执行。完成ab后,它继续执行xy
解释器使用__name__跟踪正在运行的脚本。无论您将其命名为什么,当您运行一个脚本时,解释器都会调用它"__main__",使其成为主要或“主页”脚本,在运行外部脚本后返回该脚本。
从此"__main__"脚本调用的任何其他脚本都被分配其文件名作为其__name__(例如,__name__ == "ab.py")。因此,if __name__ == "__main__":是解释器测试以确定它是否正在解释/解析最初执行的“主页”脚本,还是暂时窥视其他(外部)脚本。这使程序员可以根据直接执行还是外部调用来灵活地使脚本表现不同。

让我们逐步了解上面的代码,首先关注未缩进的行和它们在脚本中出现的顺序。请记住,函数或def块本身不会执行任何操作,直到它们被调用。如果口胡自语,解释器可能会说什么:

  • 打开 xy.py 文件作为“主文件”;在 __name__ 变量中将其命名为 "__main__"。
  • 导入并打开名称为 "ab.py" 的文件。
  • 哦,一个函数。我会记住的。
  • 好的,函数 a();我刚学过这个。打印“ab 文件中的一个函数”。
  • 文件结束;回到 "__main__"!
  • 哦,又一个函数。我会记住的。
  • 又一个。
  • 函数 x();好的,打印“外围任务:可能在其他项目中有用”。
  • 这是什么?一个 if 语句。好吧,条件已经满足(变量 __name__ 已被设置为 "__main__"),所以我将进入 main() 函数并打印“主函数:这就是行动发生的地方”。
下面两行的意思是:“如果它是'__main__'或者'home'脚本,就执行名为'main()'的函数。”这就是为什么你会看到一个在顶部包含脚本功能主流程的'main()'块。
为什么要这样做呢?还记得我之前说的导入语句吗?当你导入一个模块时,它并不仅仅是“认识”了这个模块并等待进一步指令——实际上,它运行了包含在脚本中的所有可执行操作。因此,将脚本的核心放入'main()'函数中可以有效地隔离它,将其置于隔离状态,这样当其被另一个脚本导入时,它不会立即运行。
当然,也有例外,但通常的做法是不会从外部调用'main()'。那么你可能会想:既然我们不调用'main()',那么为什么我们还要调用这个脚本呢?这是因为许多人使用独立的函数构建脚本,这些函数被设计为独立于文件中的其他代码而运行。它们稍后会在脚本的其他位置被调用。这就带我来到了这个问题:
“但是没有它代码也能运行。”

没错,这些独立的函数 可以 被从不在 main() 函数内部的内联脚本中调用。如果你习惯于 (像我一样,在编程的早期学习阶段) 构建能够做到你所需的内联脚本,并且如果你需要执行相同的操作,你会再次尝试去解决它...... 那么,你可能不习惯代码的这种内部结构,因为它更加复杂建立起来,并且阅读起来也不是那么直观。

但是那只是一个脚本,很可能不能从外部调用其函数,因为如果可以,它将立即开始计算并分配变量。而且,如果你试图重复使用一个函数,你的新脚本和旧脚本之间肯定存在密切关联,会产生冲突变量。

通过拆分出独立的函数,你可以通过调用它们到另一个脚本中重新使用你以前的工作。例如,“example.py” 可以导入 “xy.py”,并调用 x() ,利用 "xy.py" 中的 'x' 函数。(也许是将给定文本字符串的第三个单词大写;从数字列表创建NumPy数组并对其进行平方;或对3D表面进行去趋势处理。可能性是无限的。)

顺便提一下,这个问题中@kindall的回答最终帮助我理解了为什么而不是如何。不幸的是,它被标记为这个的重复,我认为这是一个错误。


97
if __name__ == '__main__': 中的代码仅在模块作为脚本运行时才会执行。举个例子,考虑以下模块 my_test_module.py:
# my_test_module.py

print('This is going to be printed out, no matter what')

if __name__ == '__main__':
    print('This is going to be printed out, only if user invokes the module as a script')

第一种可能:在另一个模块中导入my_test_module.py

# main.py

import my_test_module

if __name__ == '__main__':
    print('Hello from main.py')

现在如果您调用main.py

python main.py

>> 'This is going to be printed out, no matter what'
>> 'Hello from main.py'

请注意,只有my_test_module中的顶级print()语句会被执行。


第二种可能性:将my_test_module.py作为脚本调用

如果您将my_test_module.py作为Python脚本运行,则两个print()语句都将被执行:

python my_test_module.py

>>> 'This is going to be printed out, no matter what'
>>> 'This is going to be printed out, only if user invokes the module as a script'

如需更详细的解释,请阅读Python 中的 if __name__ == '__main__' 到底是干嘛用的?


2
Short and clear! - Scott

73

当我们希望在我们的模块(M.py)作为主程序(不是被导入)运行时执行某些语句(测试用例,打印语句),我们可以将这些语句放置在此if块下。

默认情况下(当模块作为主程序运行时而不是导入时),__name__变量被设置为"__main__",并且当它被导入时,__name__变量将获得一个不同的值,很可能是模块的名称('M')。这对于同时运行模块的不同变体以及分离它们的特定输入和输出语句以及任何测试用例非常有帮助。

简而言之,使用此'if __name__ == "main"'块可以防止(某些)代码在导入模块时运行。


有时候,只需要像这个回答中提到的一行简短语句就足够了:“简而言之,使用 'if name == "main" ' 块来防止在模块被导入时运行(某些)代码。”这非常有用。谢谢! - ZeZNiQ

68
简单来说,__name__ 是每个脚本定义的变量,用于确定脚本是作为主模块运行还是作为导入模块运行。
因此,如果我们有两个脚本;
#script1.py
print "Script 1's name: {}".format(__name__)

并且

#script2.py
import script1
print "Script 2's name: {}".format(__name__)

执行script1的输出为:
Script 1's name: __main__

执行 script2 后的输出如下:
Script1's name is script1
Script 2's name: __main__

如您所见,__name__ 告诉我们哪个代码是“主”模块。这很好,因为你可以只编写代码而不必像在C/C++中那样担心结构问题,如果一个文件没有实现“main”函数,则无法将其编译为可执行文件;如果它实现了“main”函数,则不能用作库。
比方说,您编写了一个做某件伟大事情的 Python 脚本,并实现了一堆对其他目的有用的函数。如果我想使用它们,我只需导入您的脚本,然后在不执行您的程序的情况下使用它们(前提是您的代码只在if __name__ == "__main__":上下文中执行)。而在C/C++中,您需要将这些代码片段划分到单独的模块中,然后再包含该文件。请想象以下情况:

Complicated importing in C

箭头是重要的链接。对于每个模块尝试包含先前模块代码的三个模块,有六个文件(计算实现文件共九个)和五个链接。这使得将其他代码包含到C项目中变得困难,除非它被编译为库。现在想象一下Python:

Elegant importing in Python

如果您编写了一个模块,其他人想要使用您的代码,只需导入它,__name__变量就可以帮助将程序的可执行部分与库部分分离。


2
C/C++的示例有误:三次使用了相同的单元名称(file1)。 - Wolf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接