__name__ ==“__main__” 怎么办?

if __name__ == "__main__":什么作用?

# Threading example
import time, thread

def myfunction(string, sleeptime, lock, *args):
    while True:
        lock.acquire()
        time.sleep(sleeptime)
        lock.release()
        time.sleep(sleeptime)

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))

答案

每当 Python 解释器读取源文件时,它都会做两件事:

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

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

让我们看看它是如何工作的,以及它与您在 Python 脚本中经常看到的有关__name__检查的问题之间的__name__

代码样例

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

# Suppose this is foo.py.

print("before import")
import math

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

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

print("before __name__ guard")
if __name__ == '__main__':
    functionA()
    functionB()
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 ,剥离.py ,然后将该字符串分配给模块的__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 functionA"

  2. 它执行def块,创建一个功能对象,然后将该功能对象分配给一个名为functionA的变量。

  3. 它输出字符串"before functionB"

  4. 它执行第二个def块,创建另一个功能对象,然后将其分配给名为functionB的变量。

  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 functionA
before functionB
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 functionA
before functionB
before __name__ guard
after __name__ guard

为什么这样工作?

您自然会想知道为什么有人会想要这个。好吧,有时候您想编写一个.py文件,该文件既可以供其他程序和 / 或模块用作模块,又可以作为主程序本身运行。例子:

  • 您的模块是一个库,但是您希望有一个脚本模式,在其中运行一些单元测试或演示。

  • 您的模块仅用作主程序,但具有一些单元测试,并且测试框架通过导入.py文件(如脚本)并运行特殊的测试功能来工作。您不希望它只是因为正在导入模块而尝试运行脚本。

  • 您的模块主要用作主程序,但它也为高级用户提供了程序员友好的 API。

除了这些示例之外,可以优雅地用 Python 运行脚本只是设置一些魔术变量并导入脚本。 “运行” 脚本是导入脚本模块的副作用。

思想的食物

  • 问题:我可以有多个__name__检查块吗?答:这样做很奇怪,但是这种语言不会阻止您。

  • 假设以下内容在foo2.py 。如果在命令行上说python foo2.py会发生什么?为什么?

# Suppose this is foo2.py.

def functionA():
    print("a1")
    from foo2 import functionB
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
if __name__ == "__main__":
    print("m1")
    functionA()
    print("m2")
print("t2")
  • 现在,如果你删除弄明白会发生什么__name__在检查foo3.py
# Suppose this is foo3.py.

def functionA():
    print("a1")
    from foo3 import functionB
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
print("m1")
functionA()
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")

通过将脚本作为命令传递给 Python 解释器来运行脚本时,

python myscript.py

缩进级别为 0 的所有代码都将执行。可以很好地定义已定义的函数和类,但是不会运行任何代码。与其他语言不同,没有main()函数会自动运行 - main main()函数隐式是顶层的所有代码。

在这种情况下,顶级代码是if块。 __name__是一个内置变量,其结果为当前模块的名称。但是,如果直接运行模块(如上面的myscript.py所述),则将__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__"

__name__变量(imho)的最简单解释如下:

创建以下文件。

# a.py
import b

# b.py
print "Hello World from %s!" % __name__

if __name__ == '__main__':
    print "Hello World again from %s!" % __name__

运行它们将为您提供以下输出:

$ python a.py
Hello World from b!

如您所见,导入模块时,Python 将此模块中的globals()['__name__']设置为模块名称。同样,在导入时,模块中的所有代码都在运行。由于if语句的计算结果为False因此不会执行此部分。

$ python b.py
Hello World from __main__!
Hello World again from __main__!

如您所见,执行文件时,Python 将此文件中的globals()['__name__']"__main__" 。这次, if语句的计算结果为True ,并且正在运行。

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 会话,即解释器的 Read,Eval,Print Loop 或 REPL)内部,您正在运行其"__main__"

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

if __name__ == "__main__":
    do_important()

有了以上内容,您的代码将仅在以主模块运行(或从另一个脚本有意调用)时执行。

更好的方法

不过,有一种 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__模块的说明中找到。该文本指出:

此模块表示解释程序的主程序在其中执行的(否则为匿名)范围 - 从标准输入,脚本文件或交互式提示中读取的命令。在这种环境中,惯用的 “条件脚本” 节使脚本运行:

if __name__ == '__main__':
    main()

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

if __name__ == "__main__":怎么办?

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

但是,作为唯一的特殊情况,无论您运行什么 Python 进程,如 mycode.py:

python mycode.py

否则将匿名全局命名空间的值'__main__'分配给它的__name__

因此,包括最后几行

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

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

使用此构造的另一个好处:如果程序决定何时,还可以将代码作为模块导入另一个脚本中,然后运行 main 函数:

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

在这里,有关代码的 “如何” 的机制有很多不同的看法,但是对我来说,直到我理解了 “为什么” 之后,才有意义。这对新程序员特别有用。

取得文件 “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.pyimport ab 。 import 语句在导入时立即运行模块,因此ab的操作要在xy的其余部分之前执行。用ab完成后,以xy继续。

解释器使用__name__跟踪正在运行的脚本。当您运行脚本时(无论您使用什么名称),解释器都将其称为"__main__" ,从而使其成为运行外部脚本后返回的主脚本或 “主” 脚本。

从此"__main__"脚本调用的任何其他脚本都将其文件名分配为其__name__ (例如__name__ == "ab.py" )。因此, if __name__ == "__main__":是解释程序的测试,以确定它是否正在解释 / 解析最初执行的 “home” 脚本,或者它是否正在临时窥视另一个(外部)脚本。这使程序员可以灵活地让脚本在直接执行与在外部执行之间有所不同。

让我们逐步看一下上面的代码,以了解发生了什么,首先关注未缩进的行及其在脚本中出现的顺序。请记住,函数或def块在被调用之前不会自行执行任何操作。如果自言自语,口译员可能会说:

  • 打开 xy.py 作为 “主” 文件;在__name__变量中将其称为"__main__"
  • 导入并使用__name__ == "ab.py"打开文件。
  • 哦,有功能。我会记住的。
  • 好的,函数a() ; 我才知道打印 ' ab 文件中函数 '。
  • 文件结尾;回到"__main__"
  • 哦,有功能。我会记住的。
  • 另一个。
  • 函数x() ; 好,打印 “ 外围任务:可能在其他项目中有用 ”。
  • 这是什么?一个if语句。好了,条件已经得到满足(变量__name__已设置为"__main__" ),所以我将输入main()函数并输出 ' main 函数:这是操作所在

最后两行表示:“如果这是"__main__"或'home' 脚本,则执行名为main()的函数。这就是为什么您会看到def main():顶部阻塞的原因,其中包含脚本功能的主要流程。

为什么要实施呢?

还记得我之前说的有关导入语句的内容吗?导入模块时,它不仅会 “识别” 它并等待进一步的指令 - 实际上会运行脚本中包含的所有可执行操作。因此,将脚本的内容放入main()函数中可以有效地隔离它,将其隔离,以便在被另一个脚本导入时不会立即运行。

同样,会有例外,但是通常的做法是main()通常不从外部调用。因此,您可能想知道又一件事:如果我们不调用main() ,为什么还要调用脚本呢?这是因为许多人使用独立的函数来构造脚本,这些独立的函数旨在独立于文件中的其余代码运行。然后在脚本正文中的其他位置调用它们。这使我想到了这一点:

但是代码没有它就可以工作

是的,这是对的。这些单独的函数可以main()函数中未包含的嵌入式脚本中调用。如果您习惯了(就像我在编程的早期学习阶段一样)构建可以完全满足您需要的内联脚本,并且如果您再次需要该操作,那么您将尝试再次找出它。嗯,您不习惯这种代码的内部结构,因为它的构建更加复杂并且阅读起来也不那么直观。

但这是一个脚本,可能无法从外部调用其功能,因为如果执行该脚本,它将立即开始计算和分配变量。而且,如果您想重用某个功能,则新脚本与旧脚本的关联性可能会很高,以至于变量会冲突。

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

(顺便说一句, 这个问题包含 @kindall 的答案,它最终帮助我理解了 - 原因,而不是方法。不幸的是,它被标记为与副本的副本,我认为这是错误的。)

当我们的模块( M.py )中有某些语句要在作为主模块运行(不导入)时执行时,可以将这些语句(测试用例,打印语句)放在if块下面。

默认情况下(当模块作为主模块运行而不是导入时), __name__变量设置为"__main__" ,并且在导入时, __name__变量将获得不同的值,很可能是模块的名称( 'M' )。这有助于一起运行模块的不同变体,分离其特定的输入和输出语句,以及是否存在测试用例。

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

简而言之, __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” 功能,则无法将其编译为可执行文件,如果可以,然后它不能用作库。

假设您编写的 Python 脚本功能出色,并实现了许多对其他用途有用的功能。如果我要使用它们,我可以导入您的脚本并使用它们而不执行程序(假设您的代码仅在if __name__ == "__main__":上下文中执行)。而在 C / C ++ 中,您将必须将这些部分分成一个单独的模块,然后再包含文件。如下图所示;

用C导入复杂

箭头是导入链接。对于三个试图包含先前模块代码的模块,有六个文件(九个,计算实现文件)和五个链接。除非将其专门编译为库,否则很难将其他代码包含到 C 项目中。现在将其描述为适用于 Python:

用Python优雅地导入

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

让我们以更抽象的方式看一下答案:

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

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

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

但是,当我们运行另一个模块(例如 “y.py”)时,仅运行块 A(而不运行 B),其中导入了 xy 并从那里运行代码(例如,当 “x.py” 中的函数由 y.py 调用)。