一. 装饰器
1. 装饰器的本质就是一个Python函数, 它可以让其他函数在不需要任何代码变动的前提下, 增加额外的功能. 装饰器的返回值也是一个函数对象.
2. 装饰器的应用场景: 如插入日志, 性能测试, 事物处理, 缓存等等
3. 装饰器的形成过程
第一步: 有一个需求, 要在不改变函数代码的情况下, 测试一个函数的执行时间
import time def func(): start_time = time.time() time.sleep(1) # 睡一秒, 模拟程序执行时间 end_time = time.time() print(end_time - start_time) func()
输出: 1.0002674890518188
第二步: 我有很多函数要测试, 那么不可能每一次都单独写个测试功能, 那么将第一步的功能封装成一个函数, 将要测试运行时间的函数作为参数传入, 今后要用直接调用就行了
import time # 待测试的函数 def func(): time.sleep(1)
# 测试运行时间功能 def timmer(f): start_time = time.time() f() # 待测试函数执行 end_time = time.time() print(end_time-start_time)
timmer(func)
输出: 1.0006756782531738
第三步: 假设我有100个函数都要测试, 那么每个函数测试时都要写timmer(func), 太麻烦了, 且函数的调用方式也改变了, 那么现在做第三步
import time # 待装饰函数 def func(): time.sleep(1) # 装饰器 def timmer(f): def inner(): start_time = time.time() f() # 待测试函数执行 end_time = time.time() print(end_time-start_time) return inner func = timmer(func) # 先执行timmer(func), 将inner返回给func
func() # 实际是inner()
输出: 1.0006918907165527
第四步: 经过第三步的处理, 已经将函数的调用方式改为了func(), 但还是要写func = timmer(func). 为此, 引入语法糖: @装饰器名
import time # 装饰器 def timmer(f): def inner(): start_time = time.time() f() # 待测试函数执行 end_time = time.time() print(end_time-start_time) return inner
@timmer
def func():
time.sleep(1)
func()
输出: 1.0006766319274902
二. 装饰带返回值函数的装饰器
经过第一部分的四步, 已经制作了一个不带返回值得装饰器, 如果要做一个带返回值得装饰器, 那么做出如下配置
import time # 装饰器 def timmer(f): def inner(): start_time = time.time() ret = f() # 待测试函数执行, 且将返回值赋给ret end_time = time.time() print(end_time-start_time) return ret return inner @timmer def func(): time.sleep(1) return '我是带返回值的函数, 我有装饰器了!!!' dsb = func() print(dsb)
输出:
1.0006749629974365
我是带返回值的函数, 我有装饰器了!!!
三. 装饰带参数函数的装饰器
1. 固定的参数
import time # 装饰器 def timmer(f): def inner(a): start_time = time.time() ret = f(a) # 待测试函数执行, 且将返回值赋给ret end_time = time.time() print(end_time-start_time) return ret return inner @timmer def func(a): time.sleep(1) print('我是参数a:', a) return '我是带参数且有返回值的函数, 我有装饰器了!!!' dsb = func("牛批") print(dsb)
输出:
我是参数a: 牛批
1.0006965621974372
我是带参数且有返回值的函数, 我有装饰器了!!!
2. 动态参数
import time # 装饰器 def timmer(f): def inner(*args, **kwargs): # 动态参数 start_time = time.time() ret = f(*args, **kwargs) end_time = time.time() print(end_time-start_time) return ret return inner @timmer def func(a): time.sleep(1) print('我是动态参数, 随便传') return '我是动态参数且有返回值的函数, 我TM也有装饰器了!!!' dsb = func("牛批") print(dsb)
输出:
我是动态参数, 随便传
1.0006752014160156
我是动态参数且有返回值的函数, 我TM也有装饰器了
四. 装饰器的固定格式
# 装饰器 def wrapper(f): # f是被装饰的函数 def inner(*args, **krargs) # 动态参数 你想干嘛? ret = f(*args, **kwargs) # 被装饰的函数执行 你还想干嘛? return ret
return inner # 注意这里不能加() @wrapper # 语法糖 def 被装饰函数(): ... return '我是被装饰函数'