一.程序入口
对于很多编程语言来说,程序都必须要有一个入口,比如C,C++,以及完全面向对象的编程语言Java,C#等。如果我们接触过这些语言,对于程序入口这个概念应该很好理解。
C和C++都需要有一个main函数来作为程序的入口,也就是程序的运行会从main函数开始。同样,Java和C#必须要有一个包含Main方法的主类来作为程序的入口。
而Python则不同,它属于脚本语言,不像编译型语言那样现将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。(关于解释性语言和编译型语言的区别可以看这里)
一个Python源码文件除了可以被直接运行外,还可以作为模块(也就是库)被导入。不管是导入还是直接运行,最顶层的代码都会被运行(Python用缩进来区分代码层次)。而实际上在导入的时候,有一部分代码我们是不希望被运行的。
接下来我们先举一个例子:
假设我们有一个const.py文件,内容如下:
PI = 3.14def main():print("PI:", PI)main()
我们在这个文件里面定义了一些常量,然后又写了一个main函数来输出定义的常量,最后运行main函数就相当于对定义做了一遍人工检查,看看值设置的都对不对。然后我们直接执行该文件(python const.py),输出:
PI: 3.14
现在我们有一个area.py文件,用于计算圆的面积,该文件里面需要用到const.py文件中的PI变量,那么我们从const.py中把PI变量导入到area.py中:
from const import PIdef calc_round_area(redius):return PI * (radius ** 2)def main():print("round area: ", calc_round_area(2))main()
运行area.py,输出结果:
PI: 3.14
round area: 12.56
可以看到,const中的main函数也被运行了,实际上我们是不希望它被运行,提供main也只是为了对常量定义进行一下测试。这时,if__name__ == '__ main __'就派上了用场。把const.py改一下:
PI = 3.14def main():print("PI:", PI)if __name__ == "__main__"main()
然后再运行area.py,输出如下:
round area: 12.56
再运行一下const.py,输出如下:
PI: 3.14
这些就是我们想要的效果。因为__ name __ 代表当前模块的名字,当我们再次运行“python area.py”时,对于const.py来说,__ name __ 不再是__ main __,因此其中的mian()不再被执行。
if name == ‘__ main __’ 就相当于是Python模拟的程序入口。Python本身并没有规定这么写,这只是一种编程习惯。由于模块之间相互引用,不同模块可能都有这样的定义,而入口程序只能有一个。到底哪个入口程序被选中,这取决于 __ name __ 的值。
二.__ name __
__ name __ 是内置变量,用于表示当前模块的名字,同时还能反映一个包的结构。
我们先来举一个例子,假如有下面一个包:
a
├── b
│ ├── c.py
│ └── __init__.py
└── __init__.py
目录中所有py文件的内容都为:
print(__ name __)
我们执行 python -c “import a.b.c” ,输出结果:
a
a.b
a.b.c
由此可见, __ name __ 可以清晰地反映一个模块在包中的层次。其实,所谓模块名就是import时需要用到的名字。
import tornado
import tornado.web
这里的tornado和tornado.web就被称为模块的模块名。
如果一个模块被直接运行,则其没有包结构,其 __ name __ 值为 __ main __ 。例如在上例中,我们直接运行c.py文件(python a/b/c.py),输出结果如下:
__ main __
所以,对于 if __ name __ == '__ main __'我们简单的理解是:如果模块被直接运行,则代码块被运行,如果模块是被导入的,则代码不被运行。