装饰器从入门到精通:
1.背景:年底到了,又要发年终奖了,可是怎么发比较好呢?
你碰到了一个不懂技术的老大,老大说了,把大家把写得最为
得意的一段代码拿出来跑时间,咱们凭实力说话!!!于是乎老板
把测试时间的任务交给你了,那么问题来了,到底怎么解决好呢?
2.于是乎,经过仔细思考你想到了一个方案,以前学数据结构的时候不是
测试代码效率的办法:引用系统自带的时间模块即可:
import time
start = time.time()
func()
end = time.time()
print(end - start)
3.开放封闭原则:
开放:对扩展是开放的
封闭:对修改是封闭的
4.好了不废话了,很显然,上面的代码是不满足这个原则的,接下来
今天的主角登场了,装饰器!!!
5.初识装饰器:
1 import time 2 3 4 def timmer(f): 5 def inner(): 6 start = time.time() 7 f() 8 end = time.time() 9 print(end - start) 10 11 return inner 12 13 14 def func(): 15 time.sleep(0.1) 16 # 时间太短无法测试 所以sleep一下 17 print("hello world") 18 19 20 func = timmer(func) 21 # 这里面讲func作为参数传到里面去执行了一趟!!! 22 # 返回的func实际上是inner 23 func() 24 """ 25 hello world 26 0.10023927688598633 27 """
实际上这就是一个闭包嘛,地球人真麻烦取这么多名字干嘛!!!
6.语法糖
老是这么写:func = timmer(func),实在是繁琐,于是呢人们又发明了一个
新的写法来代替上面这句话:在被装饰的函数前面加上@起装饰作用的函数
上面这个就写成这样了:
1 import time 2 3 4 def timmer(f): 5 def inner(): 6 start = time.time() 7 f() 8 end = time.time() 9 print(end - start) 10 11 return inner 12 13 14 @timmer # 相当于 func = timmer(func) 15 def func(): 16 time.sleep(0.1) 17 # 时间太短无法测试 所以sleep一下 18 print("hello world") 19 20 21 func() 22 """ 23 hello world 24 0.10023927688598633 25 """
7.参数问题
如果被装饰的函数里面有参数怎么办?装饰之后的func实际上是inner,而func又在
inner里面执行,所以我把参数给inner,顺便再返回一下就可以了。
1 import time 2 3 4 def timmer(f): 5 def inner(*args, **kwargs): 6 start = time.time() 7 ret = f(*args, **kwargs) 8 end = time.time() 9 print(end - start) 10 return ret 11 12 return inner 13 14 15 @timmer # 相当于 func = timmer(func) 16 def func(a, b): 17 time.sleep(0.1) 18 # 时间太短无法测试 所以sleep一下 19 print("hello world") 20 return a + b 21 22 23 a = func(1, 2) 24 print(a) 25 """ 26 hello world 27 0.10096383094787598 28 3 29 """
8.装饰器公式 ===>万能金刚
1 import time 2 3 4 def outer(f): 5 def inner(*args, **kwargs): 6 start = time.time() 7 ret = f(*args, **kwargs) 8 end = time.time() 9 print(start - end) 10 return ret 11 12 return inner 13 14 15 @outer 16 def func(): 17 pass
9.高阶装饰器(带参数的装饰器)
1 def route(rule, **options): # 从右往左执行 第一层实际上是传递参数 2 def decorator(f): 3 def inner(*args, **kwargs): 4 print(options) 5 # dic = 6 print({**options}) 7 # print(**options) 8 endpoint = options.pop("endpoint", f.__name__) # 弹出字典里面的值 9 print("被装饰的函数为:", endpoint) 10 print(rule) 11 res = f(*args, **kwargs) 12 print("in decorator") 13 print(id(f)) 14 return res 15 16 return inner 17 18 return decorator 19 20 21 dic = {"name": "dgf", "age": 18} 22 23 24 @route('/我是路由/', name="dgf") # 这句话等同于 func=outer(func) 25 def printIn(str): 26 # print(id(printIn)) 27 print('h') 28 return str 29 30 31 ret = printIn("hello world") 32 print(ret)
1 import time 2 3 4 def timmer_out(flag): 5 def timmer(f): 6 def inner(*args, **kwargs): 7 if flag: 8 start = time.time() 9 ret = f(*args, **kwargs) 10 end = time.time() 11 print(end - start) 12 return ret 13 else: 14 ret = f(*args, **kwargs) 15 return ret 16 17 return inner 18 19 return timmer 20 21 22 @timmer_out(True) 23 def func(): 24 time.sleep(0.1) 25 print("我是func") 26 27 28 func() 29 """ 30 我是func 31 0.10094308853149414 32 """
再将参数改为FALSE
1 import time 2 3 4 def timmer_out(flag): 5 def timmer(f): 6 def inner(*args, **kwargs): 7 if flag: 8 start = time.time() 9 ret = f(*args, **kwargs) 10 end = time.time() 11 print(end - start) 12 return ret 13 else: 14 ret = f(*args, **kwargs) 15 return ret 16 17 return inner 18 19 return timmer 20 21 22 @timmer_out(False) 23 def func(): 24 time.sleep(0.1) 25 print("我是func") 26 27 28 func() 29 """ 30 我是func 31 """
这里实际上要分两步看这个问题
10.多个装饰器装饰一个函数
1 def func1(f): 2 def inner(*args, **kwargs): 3 print("fun1 start") 4 func_ret = f() 5 print("fun1 end") 6 return func_ret 7 8 return inner 9 10 11 def func2(f): 12 def inner(*args, **kwargs): 13 print("fun2 start") 14 func_ret = f() 15 print("fun2 end") 16 return func_ret 17 18 return inner 19 20 21 def func3(f): 22 def inner(*args, **kwargs): 23 print("fun3 start") 24 func_ret = f() 25 print("fun3 end") 26 return func_ret 27 28 return inner 29 30 31 @func3 32 @func2 33 @func1 34 def func(): 35 print("func") 36 37 38 if __name__ == "__main__": 39 func() 40 41 """ 42 fun3 start 43 fun2 start 44 fun1 start 45 func 46 fun1 end 47 fun2 end 48 fun3 end 49 50 """