首页 > Python笔记 阅读数:38

Python __name__=='__main__'用法详解

如果对常见编程语言有所了解,就会知道,对于 C 和 C++ 而言,不论代码有多少行,它们都有一个相同的程序执行入口—— main 函数,而不论 main 函数处于整体代码的头部还是尾部,也不管它在众多源代码文件中的哪一个里,都有一种“纵有代码千万行,唯我独尊最先行”的感觉。类似地,Java 和 C# 中会有一个包含 main 方法的主类,作为程序入口。

然而,Python 有所不同,它属于脚本语言,会动态地逐行解释并运行。也就是说,它遵循的逻辑是“先来先到先服务”,即先来的代码先解释、先执行,并没有统一的执行入口。

通过前面的讨论可知,一个 Python 源文件除了可以被直接解释运行,还可以作为模块(Module)被另外一个 Python 文档导入执行。不管直接运行,还是被导入执行,顶层的代码都会被执行。而实际上,在作为模块被导入时,可能会有一部分代码,我们不希望它被第三方执行。这时,该怎么办呢?

下面我们用【例 1】来说明。假设在一个工程中,我们有两个 Python 文件。其中一个是 parameters.py,在这个模块中,我们定义了某些参数的值。另外一个是 calculate.py,该模块需要使用前一个模块中定义的参数。我们先来看看 parameters.py 的代码。

【例 1】自定义模块(parameters.py)
#我所在的文件是 parameters.py
PI = 3.1415926

def paraTest():         #定义测试函数
    print ("PI = n, PI)

paraTest()              #调用测试函数

仅就这个模块本身而言,不论是直接在IDE环境点击执行按钮(▶)来执行程序,还是在命令行使用 python parameters.py 来执行,结果都非常简单,如下所示:

PI = 3.1415926

上述代码自娱自乐是没有问题的,但问题往往出现在彼此协作之时。

现在假设另一个文件 calculate.py 想实现求解圆形面积的功能,需要用到 parameters.py 中的参数 PI。于是,很自然地,我们想把 parameters.py 作为第三方模块导入当前程序并为我所用,代码如下所示。
from parameters import PI
需要注意的是,作为包名,在被第三方程序导入时,不要将 Python 文件的后缀名“.py”放到导入参数中。

当前文件 calculate.py 的代码如下:
#我所在的文件是 calcalute.py

from parameters import PI                       #导入自定义的包parameters

def calc_round_area(radius):                    #定义圆形面积求解函数
    return PI * (radius ** 2)

def run():
    print ("圆形面积为:", calc_round_area(5))  #调用函数

run()
保存 calcalute.py(此时需要确保和 parameters.py 保存在同一个路径下)并执行,得到的运行结果如下:

PI = 3.1415926
圆的面积为:78.539815


从结果中可以看出,圆形面积的确是求解出来了,但在 parameters.py 中写的测试 paraTest( ) 也被执行了,而这并不是我们想要的。有没有办法解决这个问题呢?其实,办法总比问题多!

Python 解释器在执行代码时有很多内置变量,__name__ 就是其中之一,其意义是“模块名”。这个内置变量很神奇,其神奇之处在于,它的值能够“见风使舵”,懂得“内外有别”,即面对不同的对象将呈现出不同的值。

假设当前模块声明了这个内置变量,如果本模块直接执行,那么这个 __name__ 的值就为 __main__。如果它被第三方引用(即通过 import 导入),那么它的值就是这个模块名,即它所在 Python 文件的文件名(不含扩展名 .py)。

有了这个区分,就可以用逻辑判断把不想被第三方模块执行的代码“保护起来”。现在我们来改写 parameters.py(修改了第07~08行),如图 1 所示。

__name__属性值的内外有别
图 1:__name__属性值的内外有别

再次运行calcalute.py程序,结果就如我们所要的,它并没有运行在 parameters.py 中写的测试函数 paraTest( )。

程序运行结果:

圆形面积为:78.539815

出现上述结果的原因很简单。对于 calcalute.py 而言,虽然在第 02 行导入了 parameters 模块,但是在 calcalute.py 文件中,作为第三方模块的 parameters,其特有属性 __name__ 的值为 parameters,而不是 __main__,也就是说,parameters.py 文件中的第 07~08 行,由于逻辑条件为 False 而不被允许执行。

相关文章