给出以下代码,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))

推荐答案

Short Answer

它是样板代码,可以防止用户无意中调用脚本.以下是脚本中省略保护时的一些常见问题:

  • 如果在另一个脚本(例如import my_script_without_a_name_eq_main_guard)中导入无担保脚本,则第二个脚本将触发第一个脚本运行at import timeusing the second script's command line arguments.这几乎总是一个错误.

  • 如果您在无防护脚本中有一个自定义类,并将其保存到一个PICLE文件中,那么在另一个脚本中取消对其进行酸洗将触发无防护脚本的导入,问题与前面项目符号中概述的问题相同.

Long Answer

为了更好地理解这一点的重要性,我们需要后退一步,了解Python如何初始化脚本,以及它如何与其模块导入机制交互.

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

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

  • 它执行文件中的所有代码.

让我们看看这是如何工作的,以及它与您提出的关于我们在Python脚本中经常看到的__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__变量.

When Your Module Is the Main Program

如果您将模块(源文件)作为主程序运行,例如

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__" 

When Your Module Is Imported By Another

另一方面,假设其他模块是主程序,它会导入您的模块.这意味着主程序或主程序导入的其他模块中有这样一条语句:

# Suppose this is in some other main program.
import foo

解释器将搜索您的foo.py文件(同时搜索一些其他变量),在执行该模块之前,解释器将把import语句中的名称"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"

执行模块的代码

设置特殊变量后,解释器执行模块中的所有代码,每次执行一条语句.您可能希望在代码示例的旁边打开另一个窗口,以便按照下面的说明进行操作.

Always

  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".

Only When Your Module Is the Main Program

  1. 如果您的模块是主程序,那么它将看到__name__确实被设置为"__main__",并且它调用这两个函数,打印字符串"Function A""Function B 10.0".

Only When Your Module Is Imported by Another

  1. (instead)如果您的模块不是主程序,而是由另一个程序导入的,那么__name__将是"foo",而不是"__main__",它将跳过if语句的主体.

Always

  1. 在这两种情况下,它都会打印字符串"after __name__ guard".

100

总而言之,以下是两种情况下的打印内容:

# 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个文件(如脚本)并运行特殊的测试函数来工作.您不希望它仅仅因为正在导入模块就try 运行脚本.

  • 您的模块主要用作主程序,但它也为高级用户提供了一个程序员友好的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 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.
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")

Python相关问答推荐

Python 枕头上的图像背景变黑

脚注在Python中使用regex导致错误匹配

如何判断LazyFrame是否为空?

在Docker中运行HAProxy时无法获得503服务

Python中两个矩阵的自定义Hadamard风格产物

如何在Python中将returns.context. DeliverresContext与Deliverc函数一起使用?

将两只Pandas rame乘以指数

从dict的列中分钟

将pandas Dataframe转换为3D numpy矩阵

两个pandas的平均值按元素的结果串接元素.为什么?

Python虚拟环境的轻量级使用

删除字符串中第一次出现单词后的所有内容

形状弃用警告与组合多边形和多边形如何解决

多处理队列在与Forking http.server一起使用时随机跳过项目

调用decorator返回原始函数的输出

Python列表不会在条件while循环中正确随机化'

LocaleError:模块keras._' tf_keras. keras没有属性__internal_'''

ruamel.yaml dump:如何阻止map标量值被移动到一个新的缩进行?

人口全部乱序 - Python—Matplotlib—映射

Gekko中基于时间的间隔约束