if __name__ == "__main__": 怎么办? [英] What does if __name__ == "__main__": do?

查看:40
本文介绍了if __name__ == "__main__": 怎么办?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下代码,if __name__ == "__main__": 做什么?

Given the following code, what does the if __name__ == "__main__": do?

# 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

It's boilerplate code that protects users from accidentally invoking the script when they didn't intend to. Here are some common problems when the guard is omitted from a script:

  • 如果你在另一个脚本中导入了guardless脚本(例如import my_script_without_a_name_eq_main_guard),那么第二个脚本将触发第一个在导入时运行使用第二个脚本的命令行参数.这几乎总是一个错误.

  • If you import the guardless script in another script (e.g. import my_script_without_a_name_eq_main_guard), then the second script will trigger the first to run at import time and using the second script's command line arguments. This is almost always a mistake.

如果您在无保护脚本中有一个自定义类并将其保存到一个 pickle 文件中,那么在另一个脚本中取消它会触发无保护脚本的导入,与上一个项目符号中概述的问题相同.

If you have a custom class in the guardless script and save it to a pickle file, then unpickling it in another script will trigger an import of the guardless script, with the same problems outlined in the previous bullet.

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

To better understand why and how this matters, we need to take a step back to understand how Python initializes scripts and how this interacts with its module import mechanism.

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

Whenever the Python interpreter reads a source file, it does two things:

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

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

it executes all of the code found in the file.

让我们看看它是如何工作的,以及它与我们在 Python 脚本中经常看到的 __name__ 检查问题有何关联.

Let's see how this works and how it relates to your question about the __name__ checks we always see in Python scripts.

让我们使用稍微不同的代码示例来探索导入和脚本的工作原理.假设以下内容位于名为 foo.py 的文件中.

Let's use a slightly different code sample to explore how imports and scripts work. Suppose the following is in a file called 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__ 变量.

当你的模块是主程序时

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

If you are running your module (the source file) as the main program, e.g.

python foo.py

解释器会将硬编码字符串 "__main__" 分配给 __name__ 变量,即

the interpreter will assign the hard-coded string "__main__" to the __name__ variable, i.e.

# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__" 

当你的模块被另一个人导入时

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

On the other hand, suppose some other module is the main program and it imports your module. This means there's a statement like this in the main program, or in some other module the main program imports:

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

解释器将搜索您的 foo.py 文件(同时搜索一些其他变体),并且在执行该模块之前,它会分配名称 "foo" 从 import 语句到 __name__ 变量,即

The interpreter will search for your foo.py file (along with searching for a few other variants), and prior to executing that module, it will assign the name "foo" from the import statement to the __name__ variable, i.e.

# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"

执行模块代码

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

Executing the Module's Code

After the special variables are set up, the interpreter executes all the code in the module, one statement at a time. You may want to open another window on the side with the code sample so you can follow along with this explanation.

总是

  1. 它打印字符串"before import"(不带引号).

它加载math 模块并将其分配给一个名为math 的变量.这相当于将 import math 替换为以下内容(注意 __import__ 是 Python 中的一个低级函数,它接受一个字符串并触发实际导入):

It loads the math module and assigns it to a variable called math. This is equivalent to replacing import math with the following (note that __import__ is a low-level function in Python that takes a string and triggers the actual import):

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

它执行 def 块,创建一个函数对象,然后将该函数对象分配给一个名为 functionA 的变量.

It executes the def block, creating a function object, then assigning that function object to a variable called functionA.

它打印字符串"before functionB".

它执行第二个 def 块,创建另一个函数对象,然后将其分配给名为 functionB 的变量.

It executes the second def block, creating another function object, then assigning it to a variable called functionB.

它打印字符串before __name__ guard".

仅当您的模块是主程序时

  1. 如果您的模块是主程序,那么它会看到 __name__ 确实设置为 "__main__" 并调用这两个函数,打印字符串 <代码>功能 A" 和 功能 B 10.0".
  1. If your module is the main program, then it will see that __name__ was indeed set to "__main__" and it calls the two functions, printing the strings "Function A" and "Function B 10.0".

仅当您的模块被其他人导入时

  1. (相反) 如果你的模块不是主程序而是由另一个程序导入,那么 __name__ 将是 "foo",而不是 "__main__",它会跳过 if 语句的主体.
  1. (instead) If your module is not the main program but was imported by another one, then __name__ will be "foo", not "__main__", and it'll skip the body of the if statement.

总是

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

总结

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

In summary, here's what'd be printed in the two cases:

# 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 文件,它既可以被其他程序和/或模块用作模块,也可以作为主程序本身运行.示例:

Why Does It Work This Way?

You might naturally wonder why anybody would want this. Well, sometimes you want to write a .py file that can be both used by other programs and/or modules as a module, and can also be run as the main program itself. Examples:

  • 你的模块是一个库,但你想要一个脚本模式,它运行一些单元测试或演示.

  • Your module is a library, but you want to have a script mode where it runs some unit tests or a demo.

您的模块仅用作主程序,但它有一些单元测试,测试框架通过导入 .py 文件(如您的脚本)和运行特殊测试功能来工作.您不希望它仅仅因为它正在导入模块就尝试运行脚本.

Your module is only used as a main program, but it has some unit tests, and the testing framework works by importing .py files like your script and running special test functions. You don't want it to try running the script just because it's importing the module.

您的模块主要用作主程序,但它也为高级用户提供了对程序员友好的 API.

Your module is mostly used as a main program, but it also provides a programmer-friendly API for advanced users.

除了这些示例之外,在 Python 中运行脚本只是设置一些魔法变量并导入脚本,这很优雅.《奔跑》该脚本是导入脚本模块的副作用.

Beyond those examples, it's elegant that running a script in Python is just setting up a few magic variables and importing the script. "Running" the script is a side effect of importing the script's module.

  • 问题:我可以有多个 __name__ 检查块吗?答:这样做很奇怪,但语言不会阻止您.

  • Question: Can I have multiple __name__ checking blocks? Answer: it's strange to do so, but the language won't stop you.

假设以下内容在 foo2.py 中.如果在命令行中输入 python foo2.py 会发生什么?为什么?

Suppose the following is in foo2.py. What happens if you say python foo2.py on the command-line? Why?

# 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 中的 __name__ 检查会发生什么:
    • Now, figure out what will happen if you remove the __name__ check in 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")
        

        这篇关于if __name__ == "__main__": 怎么办?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆