if
语句?if __name__ == "__main__":
print("Hello, World!")
如果您要关闭一个问题,而有人应该使用这个习惯用语却没有使用,请考虑将其作为为什么在导入时Python运行我的模块,我该如何停止?的重复项进行关闭。对于那些只是没有调用任何函数或错误地期望使用名为main
的函数作为自动入口点的问题,请使用当我启动Python脚本时,为什么不运行main()函数?脚本从哪里开始运行?。
if
语句?if __name__ == "__main__":
print("Hello, World!")
如果您要关闭一个问题,而有人应该使用这个习惯用语却没有使用,请考虑将其作为为什么在导入时Python运行我的模块,我该如何停止?的重复项进行关闭。对于那些只是没有调用任何函数或错误地期望使用名为main
的函数作为自动入口点的问题,请使用当我启动Python脚本时,为什么不运行main()函数?脚本从哪里开始运行?。
这是一段样板代码,用于保护用户在不打算调用脚本时的意外调用。以下是省略了保护代码的脚本可能出现的常见问题:
如果你在另一个脚本中导入了没有保护代码的脚本(例如: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
# 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"
在设置好特殊变量之后,解释器逐条执行模块中的所有代码。您可能希望在一侧打开另一个窗口,以便可以跟随本说明进行。
始终如此
它打印字符串"before import"
(不包含引号)。
它加载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")
只有当你的模块是主程序时
只有当你的模块被其他模块导入时
__name__
将会是 "foo"
而不是 "__main__"
,并且它将跳过 if
语句的内容。总是
"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")
subprocess.run('foo_bar.py')
会发生什么?我认为foo_bar
将以__name__ = '__main__'
启动,就像我在命令提示符手动输入foo_bar.py
一样。是这种情况吗?
考虑到@MrFooz的回答,这样做不应该有任何问题,可以同时拥有尽可能多的“主”模块。即使更改了__name__
值或者独立创建实例(或者通过subprocess
相互创建实例),它们之间的交互也应该像平常一样适用于Python。
我有什么遗漏吗? - hajefsubprocess.run
的工作方式是正确的。不过,更好的一种在脚本之间共享代码的方法是创建模块,并让脚本调用共享的模块,而不是像脚本互相调用那样。 subprocess.run
的调试很困难,因为大多数调试器不能跨进程边界跳转,创建和销毁额外的进程可能会增加非微不足道的系统开销等问题。 - Mr Foozmultiprocessing
,特别是在 Windows 上需要进行这个测试。 - Yann Vernier__name__
,而不是通过将文件名中的“.py”去掉。因为Python标识符区分大小写,但文件名可能不一定如此(例如在Windows上),所以文件名中可能没有足够的信息来确定正确的Python模块名。 - Ben当您将脚本作为命令传递给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__"
。
if __name__ == "__main__":
基本上检查您是否在运行Python脚本本身,而不是导入它或其他东西? - Merp# 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
。
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__'
检查:
使用以上方法,您的代码只会在作为主模块运行时执行(或故意从其他脚本中调用它)。
不过,有一种更符合 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()
更好的方法
来说明我们如何将模块作为脚本运行,而使用 更好的方式
来说明我们如何在其他地方导入模块并仍然运行它。 - BtLutzif __name__ == "__main__"
是当脚本使用类似 python myscript.py
命令从命令行运行时运行的部分。
print("hello world")
的文件名为helloworld.py
的文件,可以通过命令python helloworld.py
运行,即使没有if __name__ == "__main__"
? - hi15python helloworld.py
时,它将运行整个脚本文件(无论你是否指定了if __name__ == "__main__"
)。只有在从另一个脚本导入helloworld.py
时才会执行不同的操作。在这种情况下,if __name__ == "__main__"
代码块根本不执行。 - Nihal Sangeethif __name__ == "__main__"的作用是什么?
__name__
是一个全局变量(在 Python 中,全局实际上是指在模块级别),存在于所有命名空间中。通常它是模块的名称(作为 str
类型)。
然而,这是唯一的特殊情况,在你运行的任何 Python 进程中,就像在 mycode.py 中:
python mycode.py
否则匿名的全局命名空间被赋值为 '__main__'
,其 __name__
属性也被设置为这个值。
因此,包括最终行。
if __name__ == '__main__':
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.py
时,你会import ab
。导入语句会立即在导入时运行模块,因此ab
的操作会在xy
的余下部分之前执行。完成ab
后,它继续执行xy
。__name__
跟踪正在运行的脚本。无论您将其命名为什么,当您运行一个脚本时,解释器都会调用它"__main__"
,使其成为主要或“主页”脚本,在运行外部脚本后返回该脚本。"__main__"
脚本调用的任何其他脚本都被分配其文件名作为其__name__
(例如,__name__ == "ab.py"
)。因此,if __name__ == "__main__":
是解释器测试以确定它是否正在解释/解析最初执行的“主页”脚本,还是暂时窥视其他(外部)脚本。这使程序员可以根据直接执行还是外部调用来灵活地使脚本表现不同。
让我们逐步了解上面的代码,首先关注未缩进的行和它们在脚本中出现的顺序。请记住,函数或def
块本身不会执行任何操作,直到它们被调用。如果口胡自语,解释器可能会说什么:
没错,这些独立的函数 可以 被从不在 main()
函数内部的内联脚本中调用。如果你习惯于 (像我一样,在编程的早期学习阶段) 构建能够做到你所需的内联脚本,并且如果你需要执行相同的操作,你会再次尝试去解决它...... 那么,你可能不习惯代码的这种内部结构,因为它更加复杂建立起来,并且阅读起来也不是那么直观。
但是那只是一个脚本,很可能不能从外部调用其函数,因为如果可以,它将立即开始计算并分配变量。而且,如果你试图重复使用一个函数,你的新脚本和旧脚本之间肯定存在密切关联,会产生冲突变量。
通过拆分出独立的函数,你可以通过调用它们到另一个脚本中重新使用你以前的工作。例如,“example.py” 可以导入 “xy.py”,并调用 x()
,利用 "xy.py" 中的 'x' 函数。(也许是将给定文本字符串的第三个单词大写;从数字列表创建NumPy数组并对其进行平方;或对3D表面进行去趋势处理。可能性是无限的。)
顺便提一下,这个问题中@kindall的回答最终帮助我理解了为什么而不是如何。不幸的是,它被标记为这个的重复,我认为这是一个错误。
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__'
到底是干嘛用的?。
当我们希望在我们的模块(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__)
Script 1's name: __main__
Script1's name is script1
Script 2's name: __main__
__name__
告诉我们哪个代码是“主”模块。这很好,因为你可以只编写代码而不必像在C/C++中那样担心结构问题,如果一个文件没有实现“main”函数,则无法将其编译为可执行文件;如果它实现了“main”函数,则不能用作库。if __name__ == "__main__":
上下文中执行)。而在C/C++中,您需要将这些代码片段划分到单独的模块中,然后再包含该文件。请想象以下情况:
箭头是重要的链接。对于每个模块尝试包含先前模块代码的三个模块,有六个文件(计算实现文件共九个)和五个链接。这使得将其他代码包含到C项目中变得困难,除非它被编译为库。现在想象一下Python:
如果您编写了一个模块,其他人想要使用您的代码,只需导入它,__name__
变量就可以帮助将程序的可执行部分与库部分分离。
if __name__
检查保护的代码仅在作为命令调用时运行,而不是在导入时运行。 如果您想使用交互式Python会话调试Python脚本,这也很有用。 您可以在交互式会话中“导入”通常作为命令运行的代码,然后手动输入代码以您喜欢的方式运行脚本中的函数/类。 - cnamejj