短答
保护用户在无意时不意外地引用剧本的锅炉牌代码。 当剧本遗漏了警卫时, 这里有一些常见的问题:
如果您在另一个脚本中导入了无保护脚本(例如 ) 。import my_script_without_a_name_eq_main_guard
))),后一脚本将触发前一脚本运行导入时和使用第二脚本命令行参数。这几乎总是一个错误。
如果您在无警卫的脚本中有自定义类, 并将其保存为泡菜文件, 那么在另一部脚本中拆开它就会触发无警卫的脚本的输入, 与前一颗子弹中描述的相同问题 。
长答答
为了更好地了解为什么和如何看待这一问题,我们需要退一步,了解Python初始化脚本的方式,以及这如何与其模块输入机制相互作用。
Python 译员读到源文件时,
让我们看看这是怎么回事 和它与你的问题有什么关系__name__
我们总是在 Python 脚本中看到检查。
代码样本
让我们使用略微不同的代码样本来探索导入和脚本是如何工作的。 假设以下是在一个名为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"
执行模块代码
设置特殊变量后, 口译员将执行模块中的所有代码, 一次执行一个语句。 您可能想要用代码样本在侧面打开另一个窗口, 以便您可以随此解释一起执行 。
总是
它印着弦"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")
它印着弦"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"
这两种情况都存在。
摘要摘要摘要
简而言之,这里是两个案例的印刷品:
# 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")