1、什么是装饰器
装饰指的是为被装饰对象添加新的功能
器指的是工具
装饰器本身可以任意可调用的对象,被装饰的对象也可以是任意可调用的对象
2、为什么要装饰器
扩展新功能:写一个函数用来为另外一个函数添加新功能,需要遵循开放封闭原则(对修改是封闭的,对扩展是开放的)
1、不修改被装饰对象的源代码
2、不修改装饰对象的调用方式
3、怎么用
例如:统计函数的时间
1.创建新功能(计算时间)的函数
满足了第一个要求,不改变源代码。但调用方式改了
2.创建装饰器,将新函数设计成闭包函数,被调用函数以参数形式传入装饰器
3.变量接受装饰器的返回值
虽然满足了2个要求,但只适应于 无参的被装饰函数.
若被装饰函数为
按照原来设计,则出错。闭包函数wrapper无参数
所以为闭包函数添加参数*args,**kwargs
最后填好返回值
4.语法糖
装饰器的语法糖:在被装饰对象的正上方单独一行写上@装饰器名字、
就会将语法糖正下方的函数对象当做参数交给装饰器。执行后得到的返回值再交给被装饰对象
5, 多个装饰器的执行顺序
如图:
解释语法自下而上。
1.先将最原始函数index 当做第一个被装饰对象交给outter装饰器
2.装饰器返回inner 闭包函数,并赋值给变量index
即
新的index = inner闭包函数。
3.将新的index函数 当做第二个被装饰对象交给timmer装饰器
4.装饰器返回wrapper闭包函数,并赋值给 变量index
即
最新的index = wrapper闭包函数
总结:
先运行outter装饰器的闭包函数inner 的代码
最后运行timmer装饰器的闭包函数 wrapper的代码
运行图:
执行是自上而下
◔疑问:为什么执行自上而下
添加时间打印函数
第一种情况:时间统计装饰器在上
打印的时间是包含outter装饰器。
第二种情况:时间统计装饰器timmer在下
打印的时间未包含outter装饰器
6、有参装饰器(第三层装饰器)
为什么要有参装饰器
如图:
新需求:再添加一个信息保存的功能,根据不同的引擎保存信息。
即需要添加一个新参数
1、装饰器outter 不能再接受其它参数(除func外)
因为outter装饰器是将index 被装饰对象当做参数。无第二个参数,也不能再添加
2、闭包函数inner也不能再添加任何参数。*arg 和 **kwarg是传递给 被装饰对象的参数。 闭包函数inner 一般只做传递
所以,在装饰器outter上再套一层装饰器
运行
装饰器最多三层。
三层装饰器:
1,第二层装饰器参数仅是 被装饰对象 的形参
2,最内层的闭包函数的参数 仅仅提供 数据传递作用, 传递给 被装饰对象
3,最外层的装饰器的参数可以有多个,提供给内部所有函数使用。