[Python] 如果__name__ ==“__main__”:做什么?



Answers

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

python myscript.py

所有处于缩进级别0的代码都会被执行。 定义的函数和类已经定义好了,但是没有任何代码可以运行。 与其他语言不同,没有main()函数可以自动运行 - main()函数隐式地包含顶层的所有代码。

在这种情况下,顶级代码是一个if块。 __name__是一个内置变量,用于计算当前模块的名称。 但是,如果模块正在直接运行(如上面的myscript.py ),则__name__被设置为字符串"__main__" 。 因此,您可以测试您的脚本是直接运行还是通过测试进行其他操作

if __name__ == "__main__":
    ...

如果你的脚本被导入到另一个模块中,它的各种函数和类定义将被导入,并且它的顶级代码将被执行,但是if子句的then-body中的代码将不会作为条件运行没有得到满足。 作为基本示例,请考虑以下两个脚本:

# 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被加载时,其__name__等于"one"而不是"__main__"

Question

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



您可以将该文件作为脚本以及可导入的模块使用

fibo.py(一个名为fibo的模块)

# Other modules can IMPORT this MODULE to use the function fib
def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

# This allows the file to be used as a SCRIPT
if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

参考: https://docs.python.org/3.5/tutorial/modules.htmlhttps://docs.python.org/3.5/tutorial/modules.html




在解释if __name__ == '__main__'之前,了解__name__是什么以及它做了什么很重要。

什么是__name__

__name__是一个DunderAlias - 可以被认为是一个全局变量(可以从模块中获取)并且以类似于global

它是由type(__name__) (产生<class 'str'> type(__name__) <class 'str'> )所指示的字符串(如上所述的全局),并且是Python 3Python 2版本的内置标准。

哪里:

它不仅可以在脚本中使用,还可以在解释器和模块/包中找到。

解释:

>>> print(__name__)
__main__
>>>

脚本:

test_file.py

print(__name__)

导致__main__

模块或包装:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

导致somefile

注意,当在包或模块中使用时, __name__取文件的名称。 没有给出实际模块或包路径的路径,但它有自己的DunderAlias __file__ ,允许这样做。

你应该看到, __name__ ,它的主文件(或程序) 总是返回__main__ ,如果它是一个模块/包,或者其他一些Python脚本运行的东西,将返回文件的名称它来自哪里。

实践:

作为一个变量意味着它的值可以被覆盖(“can”并不意味着“应该”),覆盖__name__的值将导致缺乏可读性。 所以不要这样做,出于任何原因。 如果你需要一个变量定义一个新的变量。

总是假定__name__的值为__main__或文件的名称。 再次改变这个默认值会导致更多的混淆,它会做得很好,导致问题进一步下降。

例:

>>> __name__ = 'Horrify' # Change default from __main__
>>> if __name__ == 'Horrify': print(__name__)
...
>>> else: print('Not Horrify')
...
Horrify
>>>

通常在脚本中包含if __name__ == '__main__'被认为是很好的做法。

现在回答if __name__ == '__main__'

现在我们知道__name__的行为变得更清晰了:

if给定的值为真,则if将是包含该代码块的流控制语句。 我们已经看到__name__可以使用__main__或从其中导入的文件名。

这意味着如果__name__等于__main__那么文件必须是主文件,并且必须实际运行(或者它是解释器),而不是导入到脚本中的模块或包。

如果__name__确实取得__main__的值,那么该代码块中的任何内容都将执行。

这告诉我们,如果运行的文件是主文件(或者直接从解释器运行),那么必须执行该条件。 如果它是一个包,那么它不应该,并且该值不会是__main__

模块:

__name__也可以在模块中用于定义模块的名称

变种:

也可以用__name__做其他不常见但有用的事情,有些我会在这里展示:

仅在文件是模块或包时执行:

if __name__ != '__main__':
    # Do some useful things 

如果文件是主文件,则运行一个条件,如果不是,则运行另一个条件:

if __name__ == '__main__':
    # Execute something
else:
    # Do some useful things

您也可以使用它来为包和模块提供可运行的帮助功能/实用程序,而无需精心使用库。

它还允许模块作为主脚本从命令行运行,这也是非常有用的。




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!

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

更好的方法

__name__变量指向Python解释器恰好在此刻的任何地方的名称空间。

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

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

所以如果你在执行前检查:

if __name__ == "__main__":
    do_important()

通过以上所述,只有当您将代码作为主模块运行时(或者有意从其他脚本调用它),代码才会执行​​。

更好的方式

不过,有一种Pythonic方法可以改善这一点。

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

如果我们在我们开发和测试类似这样的函数时将代码放入代码中,然后在执行以下操作后立即检查'__main__'

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

如果我们将模块作为主模块运行,我们现在有一个最终的功能用于模块的结束。

它将允许将模块及其函数和类导入到其他脚本中,而无需运行main函数,并且还允许在从不同的'__main__'模块运行时调用模块(及其函数和类),即

import important
important.main()

这个习惯用法也可以在Python文档中找到__main__模块的解释。 该文指出:

该模块代表解释器主程序执行的(否则匿名)范围 - 可以从标准输入,脚本文件或交互式提示中读取命令。 正是这种惯用的“条件脚本”节引起脚本运行的环境:

if __name__ == '__main__':
    main()



if __name__ == "__main__":基本上是顶级脚本环境,则它指定解释器('我具有最高优先级首先执行')。

'__main__'是顶级代码执行的范围的名称。 从标准输入,脚本或交互式提示读取时,模块的__name__设置为等于'__main__'

if __name__ == "__main__":
    # execute only if run as a script
    main()



系统(Python解释器)为源文件(模块)提供了许多变量。 你可以随时获得它们的值,所以,让我们关注__name__变量/属性:

当Python加载源代码文件时,它会执行其中的所有代码。 (请注意,它不调用文件中定义的所有方法和函数,但它确实定义了它们。)

尽管在解释器执行源代码文件之前,它为该文件定义了一些特殊变量; __name__是Python自动为每个源代码文件定义的特殊变量之一。

如果Python将这个源代码文件作为主程序(即您运行的文件)加载,那么它会为该文件设置一个特殊的__name__变量以获得值“__main__”

如果这是从另一个模块导入的, __name__将被设置为该模块的名称。

所以,在你的例子中:

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

意味着代码块:

lock = thread.allocate_lock()
thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

只有在您直接运行模块时才会执行; 如果另一个模块正在调用/导入它,代码块将不会执行,因为__name__的值在该特定实例中不等于“ main ”。

希望这有助于。




关于代码的机制,“如何”有很多不同之处,但对我来说,直到我理解“为什么”之前,没有任何意义。 这应该对新程序员特别有用。

取文件“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__" ,使其成为运行外部脚本后返回的主或“主”脚本。 从这个"__main__"脚本调用的任何其他脚本都将其文件名指定为__name__ (例如, __name__ == "ab.py" )。 因此, if __name__ == "__main__":是解释器的测试,以确定它是解释/解析最初执行的'home'脚本,还是暂时窥探另一个(外部)脚本。 这使得程序员可以灵活地让脚本直接执行而不是外部调用。

让我们逐步了解上述代码,了解发生了什么,首先关注不显示的行和它们在脚本中出现的顺序。 记住函数 - 或者def - 块在被调用之前不会自己做任何事情。 口译员如果自言自语,可能会说些什么:

  • 打开xy.py作为'home'文件; 在__name__变量中将其称为"__main__"
  • 使用__name__ == "ab.py"导入并打开文件。
  • 哦,一个功能。 我会记住的。
  • 好的,函数a() ; 我刚刚了解到。 打印' ab文件中功能 '。
  • 文件结束; 回到"__main__"
  • 哦,一个功能。 我会记住的。
  • 另一个。
  • 函数x() ; 好吧,打印' 外围任务:可能在其他项目中很有用 '。
  • 这是什么? 一个if语句。 那么,条件已满足(变量__name__已被设置为"__main__" ),所以我将输入main()函数并打印' 主函数:这是操作的地方 '。

最下面两行意思是:“如果这是main或'home'脚本,则执行名为main()的函数”。 这就是为什么你会看到def main(): block up top,它包含脚本功能的主要流程。

为什么执行这个?

请记住我之前所说的关于进口报表的内容 当您导入一个模块时,它不会“识别”它并等待进一步的指示 - 它实际上运行脚本中包含的所有可执行操作。 因此,将脚本中的内容放入main()函数中会有效隔离它,并将其隔离,以便在其他脚本导入时不会立即运行。

再次,会有例外,但通常的做法是main()通常不会从外部调用。 所以你可能想知道另外一件事:如果我们不调用main() ,为什么我们调用脚本呢? 这是因为许多人使用独立函数来构建脚本,这些独立函数的构建是独立于文件中其余代码运行的。 然后他们在剧本正文中的其他地方被调用。 这使我感到:

但是代码没有它

恩,那就对了。 这些单独的函数可以从不包含在main()函数中的内联脚本调用。 如果您习惯于(像我一样,在编程的早期学习阶段)来构建完全符合您需要的内联脚本,并且如果您再次需要该操作,您将尝试再次弄清楚它。 。好吧,你不习惯这种内部结构来编写代码,因为编译起来比较复杂,阅读起来不太直观。 但是这是一个脚本,可能无法在外部调用它的函数,因为如果它做了,它会立即开始计算和分配变量。 如果你想重新使用一个函数,那么很可能你的新脚本与旧脚本的关系足够紧密,以至于会存在冲突的变量。

在分离独立功能时,您可以通过将以前的工作调用到另一个脚本中来重新使用以前的工作。 例如,“example.py”可能会导入“xy.py”并调用x() ,从而使用“xy.py”中的“x”函数。 (也许它是大写给定文本字符串的第三个单词;从数字列表中创建一个numpy数组并对它们进行平方;或者去除3D曲面的趋势,可能性是无限的。)

[另外, 这个线程包含@kindall的一个答案,最终帮助我理解 - 为什么,而不是如何。 不幸的是,它被标记为这一个的重复,我认为这是一个错误。]




if __name__ == "__main__":
    main()

检查python脚本的__name__属性是否为"__main__" 。 换句话说,如果程序本身被执行,属性将是__main__ ,所以程序将被执行(在这种情况下是main()函数)。

但是,如果你的python脚本被模块使用, if语句之外的任何代码都会被执行,所以if \__name__ == "\__main__"被用来检查程序是否被用作模块,并且因此决定是否运行代码。




当你交互地运行Python时,本地__name__变量被赋值为__main__ 。 同样,当你从命令行执行一个Python模块,而不是将它导入到另一个模块时,它的__name__属性被赋值为__main__ ,而不是模块的实际名称。 通过这种方式,模块可以查看自己的__name__值来自行确定它们是如何使用的,无论是作为对其他程序的支持还是作为从命令行执行的主应用程序。 因此,以下习惯用法在Python模块中很常见:

if __name__ == '__main__':
    # Do something appropriate here, like calling a
    # main() function defined elsewhere in this module.
    main()
else:
    # Do nothing. This module has been imported by another
    # module that wants to make use of the functions,
    # classes and other useful bits it has defined.



if __name__ == "__main__":做什么?

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

然而,作为唯一的特例,在任何你运行的Python进程中,就像在mycode.py中一样:

python mycode.py

否则匿名全局名称空间被赋值为'__main__'__name__

因此,包括最后一行

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

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

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

import mycode
# ... any amount of other code
mycode.main()



如果name ==' main ':

我们经常看到__name__ == '__main__'

它检查是否正在导入模块。

换句话说,只有当代码直接运行时, if块中的代码才会被执行。 这里directly意味着not imported

让我们看看它使用一个简单的代码打印模块的名称:

# test.py
def test():
   print('test module name=%s' %(__name__))

if __name__ == '__main__':
   print('call test()')
   test()

如果我们通过python test.py直接运行代码,模块名称是__main__

call test()
test module name=__main__



Links