如果 __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个回答

60

让我们以更为抽象的方式来看待答案:

假设我们在 x.py 文件中有以下代码:

...
<Block A>
if __name__ == '__main__':
    <Block B>
...

当我们运行 x.py 时,将运行块 A 和 B。

但是当我们运行另一个模块(例如 y.py),在该模块中导入了 x.py 并从那里运行代码时(例如从 y.py 中调用 x.py 中的函数),只有块 A 被运行,而不运行块 B。


60
简而言之,您需要了解以下几点:
1. `import a` 操作实际上运行了在 `a.py` 文件中可以运行的所有内容,这意味着运行了 `a.py` 中的每一行代码。
2. 由于第 1 点的存在,在导入 `a.py` 时可能并不希望运行其中所有的内容。
3. 为了解决第 2 点问题,Python 允许您使用条件检查。
4. `__name__` 是所有 `.py` 模块中的隐式变量:
- 当导入 `a.py` 时,`a.py` 模块的 `__name__` 值设置为其文件名 ``。 - 当直接使用 `python a.py` 运行 `a.py` 时,`__name__` 的值设置为字符串 `__main__`。
5. 基于 Python 如何为每个模块设置变量 `__name__` 的机制,您知道如何实现第 3 点吗?答案非常简单,对吧?使用 `if` 条件检查:`if __name__ == "__main__": // do A`
- 然后,`python a.py` 将运行部分 `// do A` - 而 `import a` 将跳过部分 `// do A`
6. 根据您的功能需求,甚至可以使用 `if __name__ == "a"`,但很少这样做。

Python 最擅长的是第四点!其他只是基本逻辑。

我已经在这个页面上读了很多答案。如果你知道这件事,那么你肯定会理解这些答案,否则你仍然会感到困惑。


5
是的,理解第一点非常重要。从那里可以清楚地看出需要这个机制。 - ProfDFrancis

48
当你以交互方式运行Python时,本地变量__name__的值被赋为__main__。同样,当你从命令行执行Python模块而不是将其导入到另一个模块中时,它的__name__属性被赋值为__main__,而不是模块的实际名称。通过这种方式,模块可以查看它们自己的__name__值,以确定它们被用作支持另一个程序还是作为从命令行执行的主应用程序。因此,在Python模块中经常使用以下习惯用法:
if __name__ == '__main__':
    # Do something appropriate here, like calling a
    # main() function defined elsewhere in this module.
    main()
else:
    # Do nothing. This module has been imported by another
    # module that wants to make use of the functions,
    # classes and other useful bits it has defined.

46

考虑:

if __name__ == "__main__":
    main()

它检查 Python 脚本的 __name__ 属性是否为 "__main__"。换句话说,如果程序本身被执行,则该属性将是 __main__,因此程序将被执行(在这种情况下是 main() 函数)。

然而,如果你的 Python 脚本被一个模块使用,那么 if 语句之外的任何代码都会被执行。所以 if __name__ == "__main__" 只是用来检查程序是否作为一个模块使用,并决定是否运行代码。


44

在解释 if __name__ == '__main__' 的任何内容之前,了解什么是 __name__ 以及它的作用非常重要。

__name__ 是什么?

__name__ 是一个DunderAlias——可视为全局变量(可以从模块访问),并且与 global 的工作方式相似。

它是一个字符串(如上所述的全局变量),由 type(__name__) 表示(得到 <class 'str'>),并且是内置标准,适用于Python 3Python 2 版本。

在哪里使用

它不仅可用于脚本中,在解释器和模块/包中也可以找到。

解释器:

>>> print(__name__)
__main__
>>>

脚本:

test_file.py:

print(__name__)

导致__main__

模块或包:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

导致somefile

请注意,在包或模块中使用时,__name__采用文件名。实际模块或包路径的路径未给出,但有自己的DunderAlias __file__,允许此操作。

您应该看到,在主文件(或程序)中使用__name__将始终返回__main__,而如果它是模块/包或任何运行于其他Python脚本的东西,则将返回其源自的文件的名称。

练习

作为一个变量意味着它的值可以被覆盖(“可以”并不意味着“应该”),覆盖__name__的值将导致可读性下降。因此,请不要这样做,无论出于何种原因。如果需要一个变量,请定义一个新变量。

通常假定__name__的值为__main__或文件名。再次更改此默认值会导致更多混乱,而不是好处,从而在后面引起问题。

示例:

>>> __name__ = 'Horrify' # Change default from __main__
>>> if __name__ == 'Horrify': print(__name__)
...
>>> else: print('Not Horrify')
...
Horrify
>>>

通常情况下,在脚本中包含 if __name__ == '__main__' 被认为是一个好的实践。

现在来回答 if __name__ == '__main__'

现在我们了解了 __name__ 的行为,事情变得更清晰了:

if 是一个流程控制语句,如果给定的值为真,则包含执行代码块。我们已经知道 __name__ 可以使用 __main__ 或导入它的文件名。

这意味着,如果 __name__ 等于 __main__,则文件必须是主文件,实际上正在运行(或者是解释器),而不是导入到脚本中的模块或包。

如果确实如此,__name__ 将采用 __main__ 的值,然后将执行该代码块中的内容。

这告诉我们,如果正在运行的文件是主文件(或直接从解释器运行),则必须执行该条件。如果它是一个包,则不应该执行,而且此值将不是 __main__

模块

__name__ 也可以在模块中用来定义模块的名称。

变体

还可以使用 __name__ 进行其他不太常见但有用的事情,这里我将展示一些:

仅在文件为模块或包时执行

if __name__ != '__main__':
    # Do some useful things 

如果文件是主文件则运行一个条件,否则运行另一个条件

if __name__ == '__main__':
    # Execute something
else:
    # Do some useful things

你可以使用它来提供可运行的帮助函数/实用工具,而不需要繁琐地使用库。

它还允许模块作为主脚本从命令行运行,这也非常有用。


38

我认为最好深入浅出地解释一下:

__name__:Python 中的每个模块都有一个特殊属性叫做__name__。它是一个内置变量,返回模块的名称。

__main__:和其他编程语言一样,Python 也有一个执行入口,也就是主函数。 '__main__' 是顶级代码执行所在范围的名称。基本上使用 Python 模块的两种方式: 直接作为脚本运行或者导入。当一个模块作为脚本运行时,它的__name__被设置为__main__

因此,当模块作为主程序运行时,__name__属性的值被设置为__main__。否则,__name__ 的值将包含模块的名称。


38

当从命令行调用Python文件时,这是一个特殊的情况。通常用于调用"main()"函数或执行其他适当的启动代码,例如处理命令行参数。

可以用多种方式编写。另一种方式是:

def some_function_for_instance_main():
    dosomething()


__name__ == '__main__' and some_function_for_instance_main()

我并不是在说你应该在生产代码中使用它,但它可以用来说明if __name__ == '__main__'并没有什么“神奇”的地方。

这只是Python文件中调用主函数的一种约定。


7
考虑到你在代码中出现了两个问题,一是依赖副作用,二是滥用“and”关键字。 "and" 关键字通常用于检查两个布尔语句是否同时为真。由于你并不关心 “and” 的结果,使用“if”语句可以更清晰地表达你的意图。请注意,这种写法可能会被认为是不良形式。 - jpmc26
9
撇开布尔运算符的短路行为作为流程控制机制是否不好的问题,更大的问题是这根本没有回答问题。 - Mark Amery
1
@jpmc26 如果有Perl或Javascript背景的人,对于使用and作为控制语句是非常熟悉的。我对此没有任何问题。另一个类似的习惯用法是使用or来设置默认值。例如,x = input("what is your name? ") or "Nameless Person" - John Henckel
@JohnHenckel 这不是Perl或JavaScript。在Python中,在布尔语句中使用具有副作用的函数被认为是不好的形式。特别是在这种情况下,使用and没有任何好处;该函数甚至不返回值。它只会使代码更加难以理解。 - jpmc26
1
@jpmc26 我正在努力寻找一个权威的来源来支持你的观点。这个观点在哪里提到了呢?例如,在 PEP8 中是否提到我们应该避免使用 and 来控制流程,或者使用 or 来分配默认值?我尝试过谷歌搜索,但是没有找到任何相关信息。 - John Henckel
@JohnHenckel 请参考PEP 20。"显式优于隐式","可读性很重要"和"应该有一种明显的方法来做到这一点,最好只有一种方法"。你不需要有人告诉你要避免在and语句中嵌套调用。Python有构造使得这种行为对读者更加明显。这里的使用模式(如果条件为真,则执行以下代码)是if设计的唯一目的and被设计用于计算两个条件是否同时为真。这个and语句的第二个操作数甚至没有被使用。 - jpmc26

31

系统(Python解释器)为源文件(模块)提供了许多变量。您可以随时获取它们的值,因此,让我们聚焦于__name__变量/属性:

当Python加载源代码文件时,它会执行其中找到的所有代码。(请注意,它不调用文件中定义的所有方法和函数,但确实定义了它们。)

然而,在解释器执行源代码文件之前,它为该文件定义了一些特殊变量;__name__是Python自动为每个源代码文件定义的这些特殊变量之一。

如果Python将此源代码文件作为主程序(即您运行的文件)进行加载,则它会将此文件的特殊__name__变量设置为值"__main__"

如果此文件正在从另一个模块导入,则__name__将被设置为该模块的名称。

因此,在部分示例中:

if __name__ == "__main__":
   lock = thread.allocate_lock()
   thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
   thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

表示代码块:

lock = thread.allocate_lock()
thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

只有在你直接运行该模块时才会执行;如果另一个模块正在调用/导入它,则该代码块将不会执行,因为在那种情况下 __name__ 的值将不等于 "main"。

希望这可以帮到你。


你好,你是少数几个提到多线程方面的问题的人之一。我可以问一下,如果我的代码不在“main”函数外面并且没有封装在一个函数里,会发生什么?这段代码会被每个从主函数启动的新线程再次执行吗? - Welsige

29

if __name__ == "__main__":基本上是顶层脚本环境,它指定了解释器('我优先被执行')。

'__main__'是顶层代码执行的作用域名称。当从标准输入、脚本或交互式提示符中读取时,一个模块的__name__被设置为'__main__'

if __name__ == "__main__":
    # Execute only if run as a script
    main()

28

考虑:

print __name__

上述代码的输出是 __main__

if __name__ == "__main__":
  print "direct method"
上述语句是正确的并打印出"直接方法"。假设他们在另一个类中导入了这个类,它就不会打印出"直接方法",因为在导入时,它会将__name__设置为"第一个模型名称"。

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