python - 如果 __name__ == "__main__": do? 会怎样

给定以下代码,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 ),那么第二个脚本将触发第一个在导入时运行并使用第二个脚本的命令行参数。这几乎总是一个错误。
  • 如果你在guardless 脚本中有一个自定义类并将其保存到pickle 文件中,那么在另一个脚本中取消它会触发guardless 脚本的导入,与上一个项目符号中概述的问题相同。

  • 长答案
    为了更好地理解为什么以及如何重要,我们需要退一步了解 Python 如何初始化脚本以及它如何与其模块导入机制交互。
    每当 Python 解释器读取源文件时,它会做两件事:
  • 它设置了一些特殊变量,如 __name__ , 接着
  • 它执行文件中找到的所有代码。

  • 让我们看看它是如何工作的,以及它与您关于 __name__ 的问题有何关联。我们在 Python 脚本中经常看到的检查。
    代码示例
    让我们使用稍微不同的代码示例来探索导入和脚本的工作方式。假设以下内容在名为 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__变量,即
    # 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 functionA" .
  • 它执行 def块,创建一个函数对象,然后将该函数对象分配给一个名为 functionA 的变量.
  • 它打印字符串 "before functionB" .
  • 它执行第二个 def块,创建另一个函数对象,然后将其分配给名为 functionB 的变量.
  • 它打印字符串 "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 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 工作。像您的脚本和运行特殊测试功能的文件。您不希望它仅仅因为它正在导入模块而尝试运行脚本。
  • 您的模块主要用作主程序,但它也为高级用户提供了对程序员友好的 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 - 如果 __name__ == "__main__": do? 会怎样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/419163/

    相关文章:

    python - 如何检查列表是否为空?

    python - 如何执行程序或调用系统命令?

    python - 如何列出目录的所有文件?

    python - Python 的列表方法 append 和 extend 有什么区别?

    python - 在 'for' 循环中访问索引

    python - 如何安全地创建嵌套目录?

    python - @staticmethod 和 @classmethod 之间的区别

    python - 如何检查文件是否存在无异常?

    python - Python 是否有字符串 'contains' 子字符串方法?

    python - 如何按值对字典进行排序?