装饰器的形成过程
假如你要写一个计算函数执行时间的函数,代码如下:
1 import time 2 3 def func1(): 4 print('in func1') 5 6 def timer(func): 7 def inner(): 8 start = time.time() 9 func() 10 print(time.time() - start) 11 return inner 12 13 func1 = timer(func1) 14 func1()
唯一碍眼的那句话就是还要在做一次赋值调用,你觉得碍眼,python的开发者也觉得碍眼,所以就为我们提供了一句语法来解决这个问题!
1 import time 2 def timer(func): 3 def inner(): 4 start = time.time() 5 func() 6 print(time.time() - start) 7 return inner 8 9 @timer #==> func1 = timer(func1) 10 def func1(): 11 print('in func1') 12 13 14 func1()
到这里,我们可以简单的总结一下:
装饰器的本质:一个闭包函数
装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
还有最后一个问题要解决,刚刚我们讨论的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办呢?
1 def timer(func): 2 def inner(a): 3 start = time.time() 4 func(a) 5 print(time.time() - start) 6 return inner 7 8 @timer 9 def func1(a): 10 print(a) 11 12 func1(1) 13 14 装饰器——带参数的装饰器
其实装饰带参的函数并不是什么难事,但假如你有两个函数,需要传递的参数不一样呢?
1 import time 2 def timer(func): 3 def inner(*args,**kwargs): 4 start = time.time() 5 re = func(*args,**kwargs) 6 print(time.time() - start) 7 return re 8 return inner 9 10 @timer #==> func1 = timer(func1) 11 def func1(a,b): 12 print('in func1') 13 14 @timer #==> func2 = timer(func2) 15 def func2(a): 16 print('in func2 and get a:%s'%(a)) 17 return 'fun2 over' 18 19 func1('aaaaaa','bbbbbb') 20 print(func2('aaaaaa'))
现在参数的问题已经完美的解决了,可是如果你的函数是有返回值的呢?
1 import time 2 def timer(func): 3 def inner(*args,**kwargs): 4 start = time.time() 5 re = func(*args,**kwargs) 6 print(time.time() - start) 7 return re 8 return inner 9 10 @timer #==> func2 = timer(func2) 11 def func2(a): 12 print('in func2 and get a:%s'%(a)) 13 return 'fun2 over' 14 15 func2('aaaaaa') 16 print(func2('aaaaaa'))
刚刚那个装饰器已经非常完美了,但是正常我们情况下查看函数的一些信息的方法在此处都会失效
1 1 def index(): 2 2 '''这是一个主页信息''' 3 3 print('from index') 4 4 5 5 print(index.__doc__) #查看函数注释的方法 6 6 print(index.__name__) #查看函数名的方
为了不让他们失效,我们还要在装饰器上加上一点来完善它:
1 from functools import wraps 2 3 def deco(func): 4 @wraps(func) #加在最内层函数正上方 5 def wrapper(*args,**kwargs): 6 return func(*args,**kwargs) 7 return wrapper 8 9 @deco 10 def index(): 11 '''哈哈哈哈''' 12 print('from index') 13 14 print(index.__doc__) 15 print(index.__name__)
开放封闭原则
1.对扩展是开放的
为什么要对扩展开放呢?
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
装饰器的主要功能:
在不改变函数调用方式的基础上在函数的前、后添加功能。
装饰器的固定格式:
#普通版本 def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner # wraps版本 from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
带参数的装饰器
可以实现函数是否执行
1 def outer(flag): 2 def timer(func): 3 def inner(*args,**kwargs): 4 if flag: 5 print('''执行函数之前要做的''') 6 re = func(*args,**kwargs) 7 if flag: 8 print('''执行函数之后要做的''') 9 return re 10 return inner 11 return timer 12 13 @outer(False) 14 def func(): 15 print(111) 16 17 func()
多个装饰器装饰同一个函数
有些时候,我们也会用到多个装饰器装饰同一个函数的情况。
1 def wrapper1(func): 2 def inner(): 3 print('wrapper1 ,before func') 4 func() 5 print('wrapper1 ,after func') 6 return inner 7 8 def wrapper2(func): 9 def inner(): 10 print('wrapper2 ,before func') 11 func() 12 print('wrapper2 ,after func') 13 return inner 14 15 @wrapper2 16 @wrapper1 17 def f(): 18 print('in f') 19 20 f()