Loading

Python - if __name__ == "__main__":

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
posted @ 2018-08-20 11:51  听雨危楼  阅读(355)  评论(0编辑  收藏  举报