简介:装饰器本质是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下,在代码运行期间动态增加功能的方式,称之为 装饰器(Decorator),装饰器的返回值也是一个函数/类对象。
常见应用场景:
1、功能插入日志。
2、事务处理、增加缓存。
3、权限校验等。
案例:
1、基础入门装饰器案例
2、装饰器语法糖案例
3、被装饰函数多次装饰
4、被装饰函数含可变参数
5、带有参数的装饰器
6、类装饰器
入门案例:
# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发
def f():
print("2022-05-27")
def dec(fun):
def inner():
print("处理函数f执行前的增加操作")
fun()
print("处理函数f执行后的增加操作")
return inner
if __name__ == '__main__':
# 处理函数f执行前的增加操作
# 2022-05-27
# 处理函数f执行后的增加操作
f = dec(f)
f()
起因:为扩展或者丰富f()函数的执行,例如在f()函数执行前后进行增加其他操作,那么可以通过装饰器解决这个问题。
本质:将f()这个函数放到其他函数中执行。
实现步骤:
1、新增的dec()的函数,形参fun,即def dec(fun):pass
def dec(fun):
pass
2、dec中内部创建一个函数inner,这个函数内新增前置操作和后置操作,并且将dec的形参fun进行执行,并把inner返回。
def dec(fun):
def inner():
print("处理函数f执行前的增加操作")
fun()
print("处理函数f执行后的增加操作")
return inner
3、调用说明:
if __name__ == '__main__':
f = dec(f)
f()
将原函数f()当成一个函数变量传给dec(fun)的形参fun,再用新增的f变量去接收这个返回值inner,再使用f()执行。这个过程中,原函数f被当成了变量传给了fun,并返回inner这个内部函数,即闭包。再次f()时,执行了inner(),即触发分别执行了前置操作、f()、后置操作三个操作。
原理:Python中函数也是对象,可以把一个函数当成变量传入函数中,也支持返回一个函数,形成闭包,调用返回的函数,则会触发执行内部的操作。从而实现了再不修改原函数的基础上,增加扩展了功能。
装饰器语法糖:上述写法既拗口,也泯灭人性,简便的写法如下。
# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发
def dec(fun):
def inner():
print("处理函数f执行前的增加操作")
fun()
print("处理函数f执行后的增加操作")
return inner
@dec
def f():
print("2022-05-27")
if __name__ == '__main__':
# 处理函数f执行前的增加操作
# 2022-05-27
# 处理函数f执行后的增加操作
f()
即:最终形成语法糖@dec def f(): … 的方式。
细节:此处的f()看起来像是执行f(),其实是执行的主函数为dec(fun)。原函数f()只是其中执行的一部分。把@dec放到f()函数的定义处,相当于执行了语句:f = dec(f)由于dec()是一个decorator,返回一个函数,所以,原来的f()函数仍然存在,只是现在同名的f变量指向了新的函数,于是调用f()将执行新函数,即在dec()函数中返回的inner()函数。
升级版装饰器1:被装饰函数多次装饰
离被装饰的函数最近的装饰器先装饰,然后外⾯的装饰器再进⾏装饰,由内到外的装饰过程。即:f穿上dec1的衣服,再带着这身衣服去穿dec2的衣服。
# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发
def dec1(fun):
def inner():
print("处理函数f执行前的增加操作:dec1")
fun()
print("处理函数f执行后的增加操作:dec1")
return inner
def dec2(fun):
def inner():
print("处理函数f执行前的增加操作:dec2")
fun()
print("处理函数f执行后的增加操作:dec2")
return inner
@dec2
@dec1
def f():
print(f"2022-05-27")
if __name__ == '__main__':
# 处理函数f执行前的增加操作:dec2
# 处理函数f执行前的增加操作:dec1
# 2022 - 05 - 27
# 处理函数f执行后的增加操作:dec1
# 处理函数f执行后的增加操作:dec2
f()
升级版装饰器2:被装饰函数含可变参数
# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发
def dec(fun):
def inner(*args, **kw):
print("处理函数f执行前的增加操作")
fun(*args, **kw)
print("处理函数f执行后的增加操作")
return inner
@dec
def f(*args, **kwargs):
person_names = "-".join([i for i in args])
print(f"你好!{person_names}。{kwargs}。今天是2022-05-27")
if __name__ == '__main__':
# 处理函数f执行前的增加操作
# 你好!Tom - Lily。{'Jim': 'HK'}。今天是2022 - 05 - 27
# 处理函数f执行后的增加操作
# f("Tom", "Lily", Jim="HK")
# f(*("Tom", "Lily"), **{'Jim': 'HK'})
a = ("Tom", "Lily")
b = {'Jim': 'HK'}
f(*a, **b)
升级版装饰器3:带有参数的装饰器
使⽤装饰器装饰函数的时候可以传⼊指定参数;
语法格式: @装饰器外层函数名(参数,…)
使⽤带有参数的装饰器,其实是在装饰器外⾯⼜包裹了⼀个函数,使⽤该函数接收参数,返回是装饰器,因为@ 符号需要配合装饰器实例;使⽤装饰器只能接收⼀个参数,并且还是函数类型。
# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发
def dec1(flag):
def mid(fun):
def inner():
if flag:
# true 执行前置操作
print("处理函数f执行前的增加操作")
fun()
else:
# false 执行后置操作
fun()
print("处理函数f执行后的增加操作")
return inner
return mid
@dec1(3 > 2)
def f():
print(f"2022-05-27")
if __name__ == '__main__':
# 处理函数f执行前的增加操作
# 2022 - 05 - 27
f()
升级版装饰器4:类装饰器 - 装饰器还有⼀种特殊的⽤法就是类装饰器,就是通过定义⼀个类来装饰函数。
# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发
class Decorator:
def __init__(self, fun):
self.fun = fun
def __call__(self, *args, **kwargs):
print("类装饰器:执行f函数的前置操作")
self.fun()
print("类装饰器:执行f函数的后置操作")
@Decorator
def f():
print(f"2022-05-27")
if __name__ == '__main__':
# 类装饰器:执行f函数的前置操作
# 2022-05-27
# 类装饰器:执行f函数的后置操作
f()
微信公众号:玩转测试开发
欢迎关注,共同进步,谢谢!