给定以下代码,有什么作用if __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))
它是样板代码,可防止用户在无意中意外调用脚本。以下是脚本中省略守卫时的一些常见问题:
import my_script_without_a_name_eq_main_guard
为了更好地理解为什么以及这如何重要,我们需要退一步了解 Python 如何初始化脚本以及它如何与其模块导入机制交互。
每当 Python 解释器读取源文件时,它会做两件事:
__name__
让我们看看它是如何工作的,以及它与__name__我们在 Python 脚本中经常看到的检查相关的问题有什么关系。
让我们使用稍微不同的代码示例来探索导入和脚本的工作方式。假设以下内容在名为foo.py.
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__变量,即
"__main__"
# 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__变量,即
"foo"
# 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
import math
__import__
# Find and load a module given its string name, "math", # then assign it to a local variable called math. math = __import__("math")
"before functionA"
def
functionA
"before functionB"
functionB
"before __name__ guard"
仅当您的模块是主程序时
"Function A"
"Function B 10.0"
仅当您的模块被另一个导入时
if
"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
除了这些示例之外,在 Python 中运行脚本只是设置一些魔法变量并导入脚本,这很优雅。“运行”脚本是导入脚本模块的副作用。
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 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")
foo3.py
# Suppose this is foo3.py. import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters 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")