器→工具, 编程语言

Python中的if __name__ == ‘__main__’

钱魏Way · · 399 次浏览
!文章内容如有错误或排版问题,请提交反馈,非常感谢!

在学习Python的过程中,或在阅读别的写到代码时会遇到类似这样的代码:

if __name__ == "__main__":
    print("Hello World!")

我们发现即使把if __name__ == ‘__main__’去掉,程序还是照样运行。很多小伙伴只知道是这么用的,也没有深究具体的作用。

程序入口

对于很多编程语言来说,程序都必须要有一个入口,比如C,C++,以及完全面向对象的编程语言Java,C#等。如果你接触过这些语言,对于程序入口这个概念应该很好理解,C和C++都需要有一个main函数来作为程序的入口,也就是程序的运行会从main函数开始。同样,Java和C#必须要有一个包含Main方法的主类来作为程序入口。

而Python则有不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。

if __name__ == “__main__”: 本质就是一个if判断,但它又不是一个简单的if判断。即当.py文件运行时,__name__是’__main__’时运行下面if下的代码,则否不运行。当然你也可以把代码写成这样:

if __name__ == "__main__":
    print("Hello World!")
else:
    print("Hello Mars!")

__name__是什么?

__name__是Python内置的变量,它是每个Python模块必备的属性,但它的值取决于你是如何执行这段代码的。

  • 当你直接执行一段脚本的时候,这段脚本的__name__变量等于’__main__’
  • 当这段脚本被导入其他程序的时候,__name__变量等于脚本本身的名字

场景1:直接运行脚本

假设我们有一个nameScript.py,代码如下:

def myFunction():
    print('The value of __name__ is ' + __name__)


def main():
    myFunction()


if __name__ == '__main__':
    main()

直接执行这个文件后流程为:

在所有其他代码执行之前,__name__变量就被设置为’__main__’了。在此之后,通过执行def语句,函数main()和myFunction()的本体被载入。接着,因为这个if语句后面的表达式为真true,函数main()就被调用了。而main()函数又调用了myFunction(),打印出变量的值’__main__’。

场景2:从其他脚本导入

如果你需要在其他脚本里重用这个myFunction()函数,比如在importingScript.py里,我们可以将nameScript.py作为一个模组导入。

importingScript.py的内容如下:

import nameScript as ns

ns.myFunction()

这时,我们就有了两个不同的作用域:一个是importingScript的,一个是nameScript的:

在importingScript.py里,__name__变量就被设置为’__main__’。当导入nameScript的时候,Python就在本地和环境变量PATH指向的路径中寻找对应名称的.py文件,找到之后,将会运行导入的文件中的代码。

但这一次,在导入的时候,它自身的__name__变量就被设置为了’nameScript’,接下来还是一样,函数main()和myFunction()的本体被载入。然而,这一次if语句后面的表达式结果为假false,所以main()函数没有被调用。

导入完毕之后,回到importingScript.py中。现在nameScript模块中的函数定义已经被导入到当前的作用域中,于是我们通过ns.myFunction()的方式调用模块中的函数,这个函数返回的是模块内的变量的值’nameScript’。

如果你试着在importingScript中打印__name__变量的值,那当你直接执行importingScript的时候,它也会输出’__main__’。原因在于,这个变量是在importingScript的作用域中的。

__name__可以显示包路径

我们建立这样一个目录结构:

a
├──b
│   ├──c.py
│   └──__init__.py
└──__init__.py
d.py

c.py文件中的代码:

print(__name__)

d.py文件中的代码:

from a.b import c

运行d.py文件,结果为:

a.b.c

此时a.py文件的__name__属性变成了a.b.c,完完全全反映了它所在的包路径。

代码目的:测试模块里函数

由于一个脚本被引入时,自身的代码会被执行,因此我们在每个脚本里都写上一段if __name__ == ‘__main__’: 如果你希望一些代码只有在脚本被直接执行时才执行,那么就把这些代码放入到if语句块中,最常见的情形就是测试代码:

def safe_division(a, b):
    if b == 0:
        return None

    return a / b

if __name__ == '__main__':
    print(safe_division(10, 5) == 2)
    print(safe_division(10, 0) == None)

我们写完一个函数后,不免要写一些测试的代码,而这些测试的代码我们不希望他们在引入时执行,只有当我们主动执行进行测试才执行这些测试代码。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注