这是做什么的,为什么要包含 if
语句?
if __name__ == "__main__":
print("Hello, World!")
这个问题解释了代码的作用以及它是如何工作的。如果您试图关闭某人应该使用此成语而不是使用此成语的问题,请考虑将其关闭为 为什么 Python 在我导入它时运行我的模块,以及如何停止它? 反而。
原文由 Devoted 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是做什么的,为什么要包含 if
语句?
if __name__ == "__main__":
print("Hello, World!")
这个问题解释了代码的作用以及它是如何工作的。如果您试图关闭某人应该使用此成语而不是使用此成语的问题,请考虑将其关闭为 为什么 Python 在我导入它时运行我的模块,以及如何停止它? 反而。
原文由 Devoted 发布,翻译遵循 CC BY-SA 4.0 许可协议
当您的脚本通过将其作为命令传递给 Python 解释器来运行时,
python myscript.py
缩进级别为 0 的所有代码都将被执行。已定义的函数和类确实已定义,但它们的代码均未运行。与其他语言不同,没有 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
"one"
"__main__"
,它的 __name__
原文由 Adam Rosenfield 发布,翻译遵循 CC BY-SA 3.0 许可协议
4 回答4.5k 阅读✓ 已解决
1 回答3.3k 阅读✓ 已解决
4 回答3.8k 阅读✓ 已解决
3 回答2.2k 阅读✓ 已解决
1 回答4.5k 阅读✓ 已解决
1 回答3.9k 阅读✓ 已解决
1 回答2.8k 阅读✓ 已解决
简答
它是样板代码,可防止用户在无意中意外调用脚本。以下是脚本中省略守卫时的一些常见问题:
如果您在另一个脚本中导入无防护脚本(例如
import my_script_without_a_name_eq_main_guard
),那么后一个脚本将触发前者 在导入时 运行并 _使用第二个脚本的命令行参数_。这几乎总是一个错误。如果您在无保护脚本中有一个自定义类并将其保存到一个 pickle 文件中,那么在另一个脚本中将其取消腌制将触发无保护脚本的导入,与上一个项目符号中概述的问题相同。
长答案
为了更好地理解这为什么以及如何重要,我们需要退后一步来了解 Python 如何初始化脚本以及它如何与其模块导入机制进行交互。
每当 Python 解释器读取源文件时,它会做两件事:
它设置了一些特殊变量,例如
__name__
,然后它执行在文件中找到的所有代码。
让我们看看它是如何工作的,以及它与您关于
__name__
我们经常在 Python 脚本中看到的检查的问题有何关系。代码示例
让我们使用一个稍微不同的代码示例来探索导入和脚本是如何工作的。假设以下内容位于名为
foo.py
的文件中。特殊变量
当 Python 解释器读取一个源文件时,它首先定义了一些特殊的变量。在这种情况下,我们关心
__name__
变量。当你的模块是主程序时
如果您将模块(源文件)作为主程序运行,例如
解释器会将硬编码字符串
"__main__"
分配给__name__
变量,即当您的模块被另一个模块导入时
另一方面,假设某个其他模块是主程序,它会导入您的模块。这意味着在主程序中或在主程序导入的其他模块中存在这样的语句:
解释器将搜索您的
foo.py
文件(以及搜索其他一些变体),并且在执行该模块之前,它会将名称"foo"
从导入语句分配给__name__
变量,即执行模块的代码
设置特殊变量后,解释器执行模块中的所有代码,一次一条语句。您可能希望在代码示例旁边打开另一个窗口,以便您可以按照此说明进行操作。
总是
它打印字符串
"before import"
(不带引号)。它加载
math
模块并将其分配给名为math
的变量。这相当于将import math
替换为以下内容(注意__import__
是 Python 中的一个低级函数,它接受一个字符串并触发实际导入):它打印字符串
"before function_a"
。它执行
def
块,创建一个函数对象,然后将该函数对象分配给一个名为function_a
的变量。它打印字符串
"before function_b"
。它执行第二个
def
块,创建另一个函数对象,然后将其分配给一个名为function_b
的变量。它打印字符串
"before __name__ guard"
。仅当您的模块是主程序时
__name__
确实设置为"__main__"
并调用这两个函数,打印字符串"Function A"
和"Function B 10.0"
。仅当您的模块被另一个模块导入时
__name__
将是"foo"
,而不是"__main__"
,它会跳过if
语句的主体。总是
"after __name__ guard"
。概括
总而言之,以下是两种情况下打印的内容:
为什么它会这样工作?
你可能自然想知道为什么有人会想要这个。好吧,有时您想编写一个
.py
文件,该文件既可以被其他程序和/或模块用作模块,也可以作为主程序本身运行。例子:您的模块是一个库,但您希望有一个脚本模式,它可以运行一些单元测试或演示。
您的模块仅用作主程序,但它有一些单元测试,并且测试框架通过导入
.py
文件(如您的脚本)并运行特殊测试功能来工作。您不希望它仅仅因为它正在导入模块而尝试运行脚本。您的模块主要用作主程序,但它也为高级用户提供了对程序员友好的 API。
除了这些示例之外,在 Python 中运行脚本只是设置一些魔术变量并导入脚本,这很优雅。 “运行”脚本是导入脚本模块的副作用。
深思熟虑
问:我可以有多个
__name__
检查块吗?答:这样做很奇怪,但语言不会阻止你。假设以下内容在
foo2.py
中。如果你在命令行上说python foo2.py
会发生什么?为什么?__name__
签入foo3.py
会发生什么: