Python基础教程:__name__变量使用方式

可能很多同学在阅读Python源代码时会发现经常会出现if __name__ == '__main__':这样的代码,那么这样的代码起到什么作用呢?本文将为你深入解析__name__变量的含义和应用场景。

当Python解析器读源代码文件时,会做如下两件事情:

  • 设置特殊变量,如__name__

  • 执行源代码文件中的所有代码;

现在我们将焦点放到__name__变量上来,看看在Python程序中为什么要使用__name__变量。
让我们先使用一段代码示例来探索导入和脚本的工作方式。假设这些代码位于名为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解释器读取源文件时,它首先定义一些特殊变量。在这个案例中,我们关心的是__name__变量。如果将Python脚本文件作为主程序运行,也就是通过下面的命令运行foo.py。

python foo.py

Python解释器会使用下面的代码为__name__变量赋值,也就是说,__name__变量的值是__main__

__name__ = "__main__"

另一方面,假设其他模块是主程序,并且它将导入foo.py。这意味着在主程序中会有如下的语句:

import foo

Python解释器将搜索foo.py文件(以及搜索其他一些变体),在执行该模块之前,它将从import语句中将名称“ foo”分配给__name__变量,也即是使用下面的代码为__name__变量赋值。

__name__ = "foo"

设置__name__变量后,Python解释器通过一次执行一条语句的方式执行模块中的所有代码。您可能想要在代码示例侧面打开另一个窗口,以便您可以按照以下说明进行操作。
现在执行前面的代码,会输出如下内容:

before import
before functionA
before functionB
before __name__ guard
Function A
Function B 10.0
after __name__ guard

如果当前的Python脚本按着主程序的方式执行(使用python命令),那么__name__变量的值就是__main__。这样就会调用functionA和functionB函数,从而输出 “Function A” 和 “Function B 10.0”

如果foo.py脚本不是作为主程序运行,而是被另一个程序导入,则__name__变量的值是“ foo”,而不是__main__,在这种情况下,将不会调用functionA和functionB函数。不过在这种情况下,仍然会输出 after __name__ guard ,因为这条语句不属于if语句。

现在总结一下:

根据foo.py的运行方式,可能会有两种输出结果。
(1)作为主程序运行,会输出如下结果

before import
before functionA
before functionB
before __name__ guard
Function A
Function B 10.0
after __name__ guard

(2)作为模块被导入,会输出如下结果:

before import
before functionA
before functionB
before __name__ guard
after __name__ guard

可能有很多同学会有这样的疑问,为什么Python要提供这个功能呢?像C#、Java这样的编程语言并没有这样的功能啊!其实这要从Python脚本的运行机理谈起。如果Python脚本作为主程序执行,这个执行方式与Java类似。不过当导入一个Python模块就不一样了。

对于Java语言,导入一个包,也只是导入而已,除非显式调用包中的API,否则单单导入,是不会执行Java代码的。但Python就不一样了,如果使用import语句导入一个模块,其实是先执行被导入模块中的所有代码,然后才会执行当前模块的代码。

例如,下面的代码,会先执行foo.py脚本中的代码,然后才会执行print(‘current module’)

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import foo
print('current module')

执行这段代码,会输出如下的内容:
before import
before functionA
before functionB
before __name__ guard
after __name__ guard
current module

如果一个Python脚本,同时即可以作为主程序执行,也可以作为模块被导入,这就要求在模块被导入时不执行作为主程序执行时的代码,所以如果是在主程序中执行的代码,应该使用__main__变量进行判断。

关于__name__的一些疑问

有的同学问,在脚本文件中可以有多个__name__校验代码块吗?其实通常只有一个__name__校验代码块吗,但Python解析器并不会阻止你编写多个__name__校验代码块吗。

下面再给大家2段代码,看看输出结果会是什么:

# foo2.py
def functionA():
    print("a1")
    import foo2
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
if __name__ == "__main__":
    print("m1")
    functionA()
    print("m2")
print("t2")

在这段代码中导入了模块本身(foo2.py),执行代码,会输出如下结果:

t1
m1
a1
t1
t2
a2
b
a3
m2
t2

大家可以分析一下这段代码的执行过程。下面将if __name__ == "__main__":去掉,看看会发生什么。

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
# foo3.py
def functionA():
    print("a1")
    import foo3
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
print("m1")
functionA()
print("m2")
print("t2")

执行这段代码,会引起死循环吗?其实是不会的,因为Python解析器有缓存,如果一个模块在当前模块中已经被导入了,当第二次导入时,将不会再次执行被导入模块的代码,而是直接使用缓存中的内容,所以import foo3只会导致foo3.py文件中的代码作为导入模块的方式被执行一次。所以执行这段代码,输出结果如下:

t1
m1
a1
t1
m1
a1
a2
b
a3
m2
t2
a2
b
a3
m2
t2

大家可以自己分析一下程序的执行过程。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值