before
Python3.6.8 + win10
刚学Python时,你可能会经常遇到这样一行代码:
if __name__ == "__main__":
然后你可能对这行代码有点不太理解。
本篇就为你讲解这行代码的意思,为什么要写用这行代码。
我们提前准备这样一个目录结构:
D:\test\ # 目录
├─ t1.py # 文件
└─ t2.py # 文件
让模块如脚本一样运行
在Python中,可以说,每一个py文件都可以说是一个模块,那么每一个模块不仅仅能被调用,也要负责本身的逻辑,如我们在模块t1中定义了一个登录函数并实现登录注册逻辑:
# t1.py
def register():
user, pwd = input('user: ').strip(), input('pwd: ').strip()
if user == '张开' and pwd == '666':
return 1
return 0
def login(user, pwd):
if user == '张开' and pwd == '666':
return 'login successful'
return 'login error'
user, pwd = input('user: ').strip(), input('pwd: ').strip()
print(login(user, pwd))
那么,这个模块在自己使用的时候,肯定没有问题。但是有一天,这个牛逼的模块被别人使用了,在t2中调用了t1的注册功能:
# t2.py
import t1
def register():
if t1.register():
return 'register successful'
return 'register error'
print(register())
'''
user: a
pwd: a
login error
user: a
pwd: a
register error
'''
t2
的执行逻辑:在t2模块内部要实现注册的时候,想到t1不是实现了一个注册的功能了吗?我们就要避免重复造轮子,就直接调过来用了,但是问题来了,当我们在调用一个模块的时候,该模块内的代码会先执行一遍,也就是t2模块示例代码最后展示的交互结果。当t2模块内的代码执行到import t1
的时候,触发了原本t1模块的执行,t1模块内部代码从上往下执行,就执行到了登录逻辑。等登录逻辑执行完毕,程序回到t2模块继续往下执行。也就执行到了t2内部的注册函数的执行。而t2的注册函数此时又调用了t1模块的注册的函数的执行,等注册逻辑执行完毕,程序往下继续执行——没有代码,程序结束。
由上述示例可以见到,我们在t2模块调用t1模块的时候,只想调用注册函数,并不想触发t1登录逻辑的执行,那么,该怎么办呢?这就要用到了开头的那行代码了。
if name == "main":
我们首先看一下模块内自带都有哪些属性,这里以t1
为例:
# t1.py
print(dir())
'''
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
'''
在上述的打印列表内,你看到了熟悉的__name__
属性,那么我们来研究一个__name__
属性是什么鬼?
我们先在各自模块内部打印一下__name__
属性。
单独执行t1.py
文件,得到如下的打印:
print('module t1.__name__:', __name__, type(__name__))
'''
module t1.__name__: __main__ <class 'str'>
'''
单独执行t2.py
文件,得到如下的打印:
# import t1
print('module t2.__name__: ', __name__, type(__name__))
'''
module t2.__name__: __main__ <class 'str'>
通过上例可以看到,各模块各自运行的结果一致,__name__
属性都返回了一个str
类型的__main__
结果。你可能说,这没啥啊,扯半天,裤子都脱了,你就给我看这个?别急,我们放开t2模块的import t1
注释再看,注意,此时t1.py
中代码不变,运行t2.py
:
import t1
print('module t2.__name__: ', __name__, type(__name__))
'''
module t1.__name__: t1 <class 'str'>
module t2.__name__: __main__ <class 'str'>
'''
通过执行t2模块发现一个有趣的现象,在导入import t1
语句触发了t1模块的执行,但是,看看此时的t1打印是什么,没错,是t1的模块名!而单独运行t1的时候,结果仍不变,还是__main__
。
由此总结:
- 当一个模块单独执行的时候,这个模块的
__name__
属性返回的是字符串类型的__main__
。 - 当一个模块被别人导入触发执行的时候,这个模块的
__name__
属性返回的是该模块的模块名。
那么,由此可以做些手脚了,我们通过__name__返回不同的字符串(自己调用返回__main__,被调用时返回自己的模块名),来解决上面那个登录逻辑被执行的问题。那么,我们就在t1中加上一句话:
# t1.py
def register():
user, pwd = input('user: ').strip(), input('pwd: ').strip()
if user == '张开' and pwd == '666':
return 1
return 0
def login(user, pwd):
if user == '张开' and pwd == '666':
return 'login successful'
return 'login error'
if __name__ == '__main__':
user, pwd = input('user: ').strip(), input('pwd: ').strip()
print(login(user, pwd))
在t1模块中,当__name__
属性返回是字符串__main__
的时候,这说明是此次执行是t1模块单独执行,那么我们就把想要实现的逻辑放到该if语句内,表明自己调用时执行。
而当别的模块如t2调用t1的时候,t1
的__name__
属性返回了t1
的模块名,而不是__main__
,所以t1模块内部的if语句也就不会执行,这样就解决了之前的登录问题。
此时再运行t2.py
,你会发现一切都正常了:
# t2.py
import t1
def register():
if t1.register():
return 'register successful'
return 'register error'
print(register())
'''
user: 张开
pwd: 666
register successful
'''
现在,你知道if __name__ == '__main__':
是干什么的了么?
that's all