Python装饰器是什么?
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
入门装饰器之前要了解的几个知识
1. 函数可以作为参数进行传递
def func():
print('我是函数')
def ggg(fn):
fn()
ggg(func) # 这里的fnc就作为了实参进行传递 输出答案: 我是函数
2.函数可以作为返回值进行返回
def func():
def inner():
print("123")
return inner #将inner的函数地址返回
ret = func() #将inner的函数地址赋值给ret
ret() #调用ret函数也就是调用inner函数
3.函数名称可以当成变量一样进行赋值操作
def func1():
print("我是函数1")
def func2():
print("我是函数2")
func1 = func2 #将func2的地址赋值给func1
func1() # 我是函数2
我们对装饰器进行推导
比如说我们想打游戏,我想要打dnf或者lol,就可以定义两个函数。
def play_dnf():
print("你好啊,我是哥布林")
def play_lol():
print("德玛西亚")
为了升级体验,我想要开挂,那我们可以这个样子。我们雇一个管家来帮我们开挂。
def play_dnf():
print("你好啊,我是哥布林")
def play_lol():
print("德玛西亚")
def guanjia(game):
print("打开外挂")
game()
print("关闭外挂")
guanjia(play_lol)
这样子好像就Ok了,但是我们有没有发现一个问题,现在这游戏就不是我们在玩了,变成管家在帮我们玩了,那我怎么样让我能玩到这个游戏呢?可以这样。
def play_dnf():
print("你好啊,我是哥布林")
def play_lol():
print("德玛西亚")
def guanjia(game):
def inner():
print("打开外挂")
game()
print("关闭外挂")
return inner
play_lol = guanjia(play_lol) #让管家把游戏重新封装一遍,我这波把原来的游戏替换了
play_lol()
我们调整一下函数的顺序,将程序改成如下文代码这样。这就是装饰器了,它与上一段代码的效果是一样的。
def guanjia(game):
def inner():
print("打开外挂")
game()
print("关闭外挂")
return inner
@guanjia
def play_dnf():
print("你好啊,我是哥布林")
@guanjia
def play_lol():
print("德玛西亚")
play_lol() #play_lol = guanjia(play_lol); play_lol()
装饰器传参的问题
这里我们要了解两个知识点。
- *是位置参数的动态传参,用于表示不能确定个数的参数。
- ** 表示关键字的动态传参(它的形式是字典)。
- 这里的arg,kwarg只是习惯使用的形参名,可以使用其他合理形参替换。
这里的参数其实是传给内层函数inner的
def guanjia(game):
def inner(*args,**kwargs):
print(*args) #这里的*是展开运算符的意思,类似JS的* admin 123456
game()
print(kwargs) #{'gender': '男'}
return inner
@guanjia
def play_dnf():
print("你好啊,我是哥布林")
@guanjia
def play_lol():
print("德玛西亚")
play_lol("admin","123456",gender = "男")
装饰器的返回值
如果被装饰的函数要有返回值我们得怎么操作呢?
def guanjia(game):
def inner(*args,**kwargs):
print("打开外挂")
ret = game()
print("关闭外挂")
return ret
return inner
@guanjia
def play_dnf():
print("你好啊,我是哥布林")
@guanjia
def play_lol():
print("德玛西亚")
return "金色的装备"
ret = play_lol("admin","123456")
print(ret)
输出结果
打开外挂
德玛西亚
关闭外挂
金色的装备
如果要传参
def guanjia(game):
def inner(*args,**kwargs):
print("打开外挂")
ret = game(*args,**kwargs)
print("关闭外挂")
return ret
return inner
@guanjia
def play_dnf():
print("你好啊,我是哥布林")
@guanjia
def play_lol(username,password):
print(f"你的用户名是{username},你的密码是{password}")
return "金色的装备"
ret = play_lol("admin","123456")
print(ret)
装饰器的通用写法
"""
装饰器: -->要求记住最后的结论
装饰器本质上是一个闭包
作用:
在不改变原有函数调用的情况下,给函数增加新的功能,
直白:可以在函数前后添加新功能,但不更改源代码
在用户登录的地方,日志,..
通用装饰器的写法:
def wrapper(fn): # wrapper:装饰器,fn:目标函数
def inner(*args,**kwargs):
#在目标函数执行之前....
ret = fn(*args,**kwargs)
#在目标函数执行之后....
return ret
return inner 千万别加()
@wrapper
def target():
pass
target() # => inner()
"""
多个装饰器的运行结果
def wrapper1(fn):
def inner(*args,**kwargs):
print("这里是wrapper1进入")
ret = fn(*args,**kwargs)
print("这里是wrapper1退出")
return ret
return inner
def wrapper2(fn):
def inner(*args,**kwargs):
print("这里是wrapper2进入")
ret = fn(*args,**kwargs)
print("这里是wrapper2退出")
return ret
return inner
@wrapper1 # target = wrapper1(wrapper2.inner) => target:wrapper1.inner
@wrapper2 # target = wrapper2(target) => target:wrapper2.inner
def target():
print("我是目标")
target()
运行结果
这里是wrapper1进入
这里是wrapper2进入
我是目标
这里是wrapper2退出
这里是wrapper1退出
装饰器的实战小demo
login_flag = False
def loginVerify(target):
def inner(*args,**kwargs):
global login_flag
if login_flag == False:
while 1:
print("还未完成登录操作")
username = input(">>>>")
password = input(">>>>")
if(username == 'admin' and password == '123456'):
print("登录成功")
login_flag = True
break
else:
print("登录失败,用户名或者密码错误")
ret = target(*args,**kwargs)
return ret
return inner
@loginVerify
def insert():
print("增加数据")
@loginVerify
def delete():
print("删除数据")
@loginVerify
def update():
print("更新数据")
@loginVerify
def search():
print("搜索数据")
insert()
delete()
update()
search()