看完这个你一定会Python装饰器
我也是一步步学来的,最初看到这个装饰器很不理解,但是通过这个例子后,我就明白了一些。先引入一个例子,里面会牵扯到其它一点基本知识,可能有些表述不准确,但是不影响对python装饰器的理解,望采纳(文中若有纰漏,多多包涵)
account = {'isTrue': False, 'name': 'Alex', 'password': '123'}
def login():
if not account['isTrue']:
if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
account['isTrue'] = True
print('输入正确,正在登陆......')
else:
print('输入错误')
else:
print('检验已经登陆过账号,登陆中......')
def content():
print('=======欢迎进入首页=======')
def net_game():
print('欢迎进入网络游戏')
def console_game():
print('欢迎进入单机游戏')
def relax_game():
print('欢迎进入休闲游戏')
def other_game():
print('欢迎进入其它游戏')
content()
net_game()
relax_game()
以上类似于进入不同游戏专区的脚本,现在需要增加一个功能,就是需要正确的账号跟密码才能进入特定专区,如:网络游戏专区、休闲游戏。总的来说,要秉承封闭与开放的原则。封闭是指:已实现的的功能代码块不应该被修改。开放是指:对现有功能的扩展开放。先一步步来, 如果不考虑封闭与开放原则,为了满足功能,可以把程序改为:
account = {'isTrue': False, 'name': 'Alex', 'password': '123'}
def login():
if not account['isTrue']:
if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
account['isTrue'] = True
print('输入正确,正在登陆......')
else:
print('输入错误')
else:
print('检验已经登陆过账号,登陆中......')
def content():
print('=======欢迎进入首页=======')
def net_game():
login()
print('欢迎进入网络游戏')
def console_game():
print('欢迎进入单机游戏')
def relax_game():
login()
print('欢迎进入休闲游戏')
def other_game():
print('欢迎进入其它游戏')
content()
net_game()
relax_game()
上面程序满足了要实现的功能,但是,违反了“开放封闭原则”。因此可以采用高阶函数的方法,即把一个函数当做参数传递给另一个函数,如下:
account = {'isTrue': False, 'name': 'Alex', 'password': '123'}
def login(func):
if not account['isTrue']:
if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
account['isTrue'] = True
print('输入正确,正在登陆......')
func()
else:
print('输入错误')
else:
print('检验已经登陆过账号,登陆中......')
func()
def content():
print('=======欢迎进入首页=======')
def net_game():
print('欢迎进入网络游戏')
def console_game():
print('欢迎进入单机游戏')
def relax_game():
print('欢迎进入休闲游戏')
def other_game():
print('欢迎进入其它游戏')
content()
login(net_game)
login(relax_game)
但是,又有一个问题,我们改变了调用方式(就是这里login(net_game))。若是有100个专区,那就要更改100个调用方式。。。。仔细分析login(net_game),这里相当于已经执行完成了(这是一个”过程“)。而这个”过程“相当于完成的就是专区的验证。
此时若进行net_game = login(net_game)。由于login(net_game)只是完成的一个“过程”,没有返回值,此时net_game的类型是None,可以通过print(type(net_game))获知,因此再执行net_game(),就会报错。回想闭包的原理,我们可以吧login(net_game)这一步变成一个“闭包”,即:
def inner():
if not account['isTrue']:
if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
account['isTrue'] = True
print('输入正确,正在登陆......')
func()
else:
print('输入错误')
else:
print('检验已经登陆过账号,登陆中......')
func()
return inner
此时,执行完login(net_game)返回的是inner,是一个函数地址,我们把这个地址给net_game。此时再执行net_game(),就顺利执行了login(net_game) 这一“过程”。net_game = login(net_game)又可以简化为:@login。代码如下
account = {'isTrue': False, 'name': 'Alex', 'password': '123'}
def login(func):
def inner():
if not account['isTrue']:
if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
account['isTrue'] = True
print('输入正确,正在登陆......')
func()
else:
print('输入错误')
else:
print('检验已经登陆过账号,登陆中......')
func()
return inner
def content():
print('=======欢迎进入首页=======')
@login
def net_game():
print('欢迎进入网络游戏')
def console_game():
print('欢迎进入单机游戏')
@login
def relax_game():
print('欢迎进入休闲游戏')
def other_game():
print('欢迎进入其它游戏')
content()
net_game()# 实际执行的inner()
relax_game()# 实际执行的inner()
以上就实现了装饰函数。但是,此时若要在net_game里面加上参数呢?好比这样:
def net_game(key):
if key > 3:
print('欢迎进入网络游戏的高级模式')
else:
print('欢迎进入网络游戏')
那此时调用net_game()时可以加参数了,好比net_game(4),但是inner()不识别呀,因此把inner也加上inner(x),下面的func(x)也是如此
但是,问题又来了,此时relax_game()不需要参数啊,因此可以把inner更改为随机数量的参数,即:inner(*args, **kwargs),下面func(*args, **kwargs)。这样就可以代表不限制执行时inner()的参数的数量了。最后程序如下:
account = {'isTrue': False, 'name': 'Alex', 'password': '123'}
def login(func):
def inner(*args, **kwargs):
if not account['isTrue']:
if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
account['isTrue'] = True
print('输入正确,正在登陆......')
func(*args, **kwargs)
else:
print('输入错误')
else:
print('检验已经登陆过账号,登陆中......')
func(*args, **kwargs)
return inner
def content():
print('=======欢迎进入首页=======')
# @pay 假如有多个装饰器,则先执行最上面的,依次执行
@login # 装饰器或者叫语法糖
def net_game(key):
if key > 3:
print('欢迎进入网络游戏的高级模式')
else:
print('欢迎进入网络游戏')
def console_game():
print('欢迎进入单机游戏')
@login #
def relax_game():
print('欢迎进入休闲游戏')
def other_game():
print('欢迎进入其它游戏')
content()
net_game(4)# 实际执行的inner()
relax_game()# 实际执行的inner()