Py学习  »  Python

如何使用uu name_uuuu==”uuuu main_uuu“来编写python脚本[副本]

Tian • 4 年前 • 1561 次点击  

什么是 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))
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/49248
 
1561 次点击  
文章 [ 29 ]  |  最新文章 4 年前
Peter Mortensen preetika monda
Reply   •   1 楼
Peter Mortensen preetika monda    5 年前

简单地说, __name__ 是为每个脚本定义的变量,用于定义脚本是作为主模块运行还是作为导入模块运行。

如果我们有两个剧本;

#script1.py
print "Script 1's name: {}".format(__name__)

#script2.py
import script1
print "Script 2's name: {}".format(__name__)

执行script1的输出是

Script 1's name: __main__

执行script2的输出是:

Script1's name is script1
Script 2's name: __main__

如你所见, __姓名__ 告诉我们哪个代码是“主”模块。 这很好,因为您可以编写代码,而不必担心C/C++中的结构问题,如果文件没有实现“主”函数,那么它就不能编译成可执行文件,如果是,它就不能用作库。

假设您编写了一个Python脚本,它做了一些很好的事情,并且实现了大量的函数,这些函数对于其他目的很有用如果我想使用它们,我可以直接导入脚本并在不执行程序的情况下使用它们(假设您的代码只在 if __name__ == "__main__": 上下文)。而在C/C++中,你必须将这些部分分割成一个单独的模块,然后包含该文件。想象一下下面的情况;

Complicated importing in C

箭头是导入链接对于每个试图包含前面模块代码的三个模块,有六个文件(九个,包括实现文件)和五个链接。这使得很难将其他代码包含到C项目中,除非它是作为库专门编译的。现在为Python设想一下:

Elegant importing in Python

你编写一个模块,如果有人想使用你的代码,他们只需要导入它,然后 __姓名__ 变量可以帮助分离程序的可执行部分和库部分。

Peter Mortensen preetika monda
Reply   •   2 楼
Peter Mortensen preetika monda    5 年前

当我们的模块中有某些语句时( M.py )我们希望在它作为main运行时执行(不是导入的),我们可以将这些语句(测试用例、打印语句)放在 if 封锁。

默认情况下(当模块作为主模块运行时,不导入) __name__ 变量设置为 "__main__" ,当它被导入时 __姓名__ 变量将得到一个不同的值,很可能是模块的名称( 'M' ). 这有助于将模块的不同变体一起运行,并分离它们的特定输入和输出语句,以及是否有任何测试用例。

简而言之 ,使用此' if __name__ == "main" '阻止(某些)代码在导入模块时运行。

joechoj
Reply   •   3 楼
joechoj    5 年前

这里有很多关于代码机制的不同看法,比如“如何”,但对我来说,在我理解“为什么”之前,这一切都没有意义这对新程序员尤其有帮助。

获取文件“ab.py”:

def a():
    print('A function in ab file');
a()

以及第二个文件“xy.py”:

import ab
def main():
    print('main function: this is where the action is')
def x():
    print ('peripheral task: might be useful in other projects')
x()
if __name__ == "__main__":
    main()

这段代码到底在做什么?

当你执行 xy.py ,你 import ab . import语句在导入时立即运行模块,因此 ab 的操作在 xy 一旦完成 ab公司 ,它继续 xy型 .

解释器跟踪运行的脚本 __name__ . 当你运行一个脚本时,不管你给它起了什么名字,解释器都会调用它 "__main__" ,使其成为运行外部脚本后返回的主脚本或“主”脚本。

从这里调用的任何其他脚本 “主要” 将脚本的文件名指定为 __姓名__ (例如。, __name__ == "ab.py" ). 因此,这条线 if __name__ == "__main__": 是解释器的测试,以确定它是在解释/解析最初执行的“home”脚本,还是临时窥视另一个(外部)脚本这就为程序员提供了灵活性,使脚本在直接执行与外部调用时有不同的行为。

让我们逐步了解上面的代码以了解发生了什么,首先关注未缩进的行以及它们在脚本中的显示顺序。记住那个功能-或者 def -块在被调用之前不会自己做任何事情。如果口译员自言自语地说:

  • 打开xy.py作为“home”文件;调用它 “主要” __姓名__ 变量。
  • 导入并打开文件 __name\uuuu=“ab.py”名称 .
  • 哦,一个函数我会记住的。
  • 好的,功能 a() ;我刚学会打印' ab文件中的一个函数 '.
  • 文件结尾;返回 “主要” !
  • 哦,一个函数我会记住的。
  • 另一个。
  • 功能 x() ;好,打印' 外围任务:可能在其他项目中有用 '.
  • 这是什么?一个 if 陈述嗯,条件已经满足了(变量 __姓名__ 已设置为 “主要” ),所以我将进入 main() 功能和打印 主要功能:动作在这里 '.

最后两行的意思是:“如果这是 “主要” 或者“home”脚本,执行 主() ". 所以你会看到 def main(): 阻塞top,它包含脚本功能的主要流程。

为什么要这么做?

还记得我之前说过的关于导入语句的话吗?当您导入一个模块时,它不仅仅是“识别”它并等待进一步的指令——它实际上运行脚本中包含的所有可执行操作。所以,把你剧本的精华放进 主() 函数有效地隔离它,使其处于隔离状态,以便在被另一个脚本导入时不会立即运行。

同样,也会有例外,但通常的做法是 主() 通常不会被外部调用所以你可能还想知道一件事:如果我们不打电话 主() ,为什么我们要调用脚本?这是因为许多人用独立的函数构造他们的脚本,这些函数是独立于文件中的其他代码运行的他们后来在剧本的其他地方被调用这让我想到:

但如果没有密码的话

是的,没错这些独立的功能 可以 从不包含在 主() 功能。如果你习惯了(就像我一样,在我早期的编程学习阶段)构建符合你需要的内联脚本,并且如果你再次需要这个操作,你会再次尝试找出答案。。。好吧,你不习惯代码的这种内部结构,因为构建起来更复杂,阅读起来也没那么直观。

但这是一个脚本,可能无法在外部调用它的函数,因为如果它这样做了,它将立即开始计算和分配变量如果你试图重新使用一个函数,那么你的新脚本和旧脚本的关系非常密切,可能会有冲突的变量。

在分离独立的函数时,通过将它们调用到另一个脚本中,可以获得重用以前工作的能力。例如,“example.py”可以导入“xy.py”并调用 x() ,使用“xy.py”中的“x”函数(可能是将给定文本字符串的第三个单词大写;从数字列表中创建NumPy数组并将其平方;或者取消三维曲面的格式可能性是无限的。)

(作为旁白, this question 包含一个@kindall的答案,它最终帮助我理解了为什么,而不是如何。不幸的是它被标记为 this one ,我认为这是个错误。)

coffee-grinder Aaron Hall
Reply   •   4 楼
coffee-grinder Aaron Hall    7 年前

什么? if __name__ == "__main__": 是吗?

__name__ 是一个全局变量(在Python中,global实际上指 module level )存在于所有名称空间中。它通常是模块的名称(作为 str 类型)。

但是,作为唯一的特殊情况,在您运行的任何Python进程中,如mycode.py:

python mycode.py

否则,将为匿名全局命名空间分配 '__main__' 对其 __姓名__ .

因此,包括 the final lines

if __name__ == '__main__':
    main()
  • 在mycode.py脚本的末尾,
  • 当它是由Python进程运行的主入口点模块时,

将导致脚本的唯一定义 main 要运行的函数。

使用此构造的另一个好处:您还可以将代码作为模块导入到另一个脚本中,然后在程序决定以下情况时运行主函数:

import mycode
# ... any amount of other code
mycode.main()
Mark Amery Harley Holcombe
Reply   •   5 楼
Mark Amery Harley Holcombe    8 年前

if __name__ == "__main__" 是当脚本从命令行运行(比如说)时使用类似于 python myscript.py .

Aaron Hall
Reply   •   6 楼
Aaron Hall    6 年前

什么是 if __name__ == "__main__": 是吗?

概述基本知识:

  • 全局变量, __name__ ,在作为程序入口点的模块中,是 '__main__' . 否则,它就是导入模块的名称。

  • 所以,在 if 只有当模块是程序的入口点时,块才会运行。

  • 它允许其他模块导入模块中的代码,而不必在导入时执行下面的代码块。


为什么我们需要这个?

开发和测试代码

假设您正在编写一个设计为用作模块的Python脚本:

def do_important():
    """This function does something very important"""

能够 通过将此函数调用添加到底部来测试模块:

do_important()

运行它(在命令提示符下)的方法如下:

~$ python important.py

问题

但是,如果要将模块导入到另一个脚本:

import important

在导入时 do_important 函数将被调用,因此您可能会注释掉函数调用, do_important() ,在底部。

# do_important() # I must remember to uncomment to execute this!

然后你必须记住你是否已经注释掉了你的测试函数调用这种额外的复杂性意味着你可能会忘记,使你的开发过程更加麻烦。

更好的方法

这个 __姓名__ 变量指向当前Python解释器所在的名称空间。

在导入的模块中,它是该模块的名称。

但是在主模块(或交互式Python会话,即解释器的Read、Eval、Print Loop或REPL)中,您正在运行 "__main__" .

因此,如果在执行之前检查:

if __name__ == "__main__":
    do_important()

使用上面的代码,您的代码将只在作为主模块运行时执行(或者故意从另一个脚本调用它)。

更好的方法

不过,有一种蟒蛇式的方法可以改进这一点。

如果我们想从模块外部运行这个业务流程呢?

如果我们在开发和测试这样一个函数时将要执行的代码放在这样一个函数中,然后检查 '''.''Mi'Ny'' 紧接着:

def main():
    """business logic for when running this module as the primary one!"""
    setup()
    foo = do_important()
    bar = do_even_more_important(foo)
    for baz in bar:
        do_super_important(baz)
    teardown()

# Here's our payoff idiom!
if __name__ == '__main__':
    main()

现在,我们有一个模块末尾的final函数,如果我们将该模块作为主模块运行,它将运行。

它将允许在不运行 main 函数,还将允许在从不同的 '''.''Mi'Ny'' 模块,即。

import important
important.main()

This idiom can also be found in the Python documentation in an explanation of the __main__ module. 该文本指出:

此模块表示(否则为匿名)作用域,其中 解释器的主程序执行从 标准输入、来自脚本文件或来自交互提示。它 在这种环境中 使脚本运行:

if __name__ == '__main__':
    main()
pi.
Reply   •   7 楼
pi.    5 年前

最简单的解释 __name__ 变量(imho)如下:

创建以下文件。

# a.py
import b

# b.py
print "Hello World from %s!" % __name__

if __name__ == '__main__':
    print "Hello World again from %s!" % __name__

运行它们将获得以下输出:

$ python a.py
Hello World from b!

如您所见,当导入模块时,Python将 globals()['__name__'] 在这个模块中以模块的名字命名此外,在导入时,模块中的所有代码都将运行作为 if 语句的计算结果为 False 此部分未执行。

$ python b.py
Hello World from __main__!
Hello World again from __main__!

如您所见,在执行文件时,Python设置 globals()['''uuu name'] 在这个文件中 "__main__" . 这一次 如果 语句的计算结果为 True 正在逃跑。

Tonechas Adam Rosenfield
Reply   •   8 楼
Tonechas Adam Rosenfield    6 年前

当通过将脚本作为命令传递给Python解释器来运行脚本时,

python myscript.py

将执行缩进级别为0的所有代码定义的函数和类是定义好的,但它们的代码都不能运行不像其他语言 main() 自动运行的函数- 主() 函数隐式地表示顶层的所有代码。

在本例中,顶级代码是 if 封锁。 __name__ 是一个内置变量,其计算结果为当前模块的名称但是,如果直接运行模块(如 myscript.py 以上),然后 __姓名__ 而是设置为字符串 "__main__" . 因此,可以通过测试来测试脚本是直接运行还是由其他东西导入

if __name__ == "__main__":
    ...

如果您的脚本被导入到另一个模块中,则会导入其各种函数和类定义,并执行其顶层代码,但是 如果 由于不满足条件,上面的子句将无法运行。作为基本示例,请考虑以下两个脚本:

# file one.py
def func():
    print("func() in one.py")

print("top-level in one.py")

if __name__ == "__main__":
    print("one.py is being run directly")
else:
    print("one.py is being imported into another module")
# file two.py
import one

print("top-level in two.py")
one.func()

if __name__ == "__main__":
    print("two.py is being run directly")
else:
    print("two.py is being imported into another module")

现在,如果您调用解释器作为

python one.py

输出将是

top-level in one.py
one.py is being run directly

如果你跑 two.py 相反:

python two.py

你得到

top-level in one.py
one.py is being imported into another module
top-level in two.py
func() in one.py
two.py is being run directly

因此,当模块 one 加载,它的 __姓名__ 等于 "one" 而不是 “主要” .

Mr Fooz
Reply   •   9 楼
Mr Fooz    4 年前

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

  • 它设置了一些特殊的变量,比如 __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 interpeter读取源文件时,它首先定义一些特殊变量在这种情况下,我们关心的是 __姓名__ 变量。

当你的模块是主程序时

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

python foo.py

解释器将分配硬编码字符串 "__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

在这种情况下,解释器将查看模块的文件名, 食品 ,剥去 .py ,并将该字符串分配给模块的 __姓名__ 变量,即。

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

执行模块代码

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

总是

  1. 它会打印出绳子 "before import" (不带引号)。

  2. 它装载 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. 它执行第二个 定义 块,创建另一个函数对象,然后将其分配给名为 functionB .

  5. 它会打印出绳子 "before __name__ guard" .

只有当你的模块是主程序时

  1. 如果你的模块是主程序,那么它会看到 __姓名__ 确实被设定为 “主要” 它调用两个函数,打印字符串 "Function A" "Function B 10.0" .

只有当您的模块被另一个模块导入时

  1. ( 相反 )如果您的模块不是主程序,而是由另一个程序导入的,则 __姓名__ "foo" ,不是 “主要” ,它将跳过 if 陈述。

总是

  1. 它会打印字符串 "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中运行脚本只是设置一些魔术变量并导入脚本,这是很优雅的。”运行“脚本是导入脚本模块的副作用。

思想食粮

  • 问题:我可以要多个吗 __姓名__ 检查积木回答:这样做很奇怪,但语言不会阻止你。

  • 假设下面是 foo2.py . 如果你说 python foo2.py 在命令行上?为什么?

# Suppose this is foo2.py.

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.

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