一,什么是装饰器?
装饰器本质上就是一个python函数,他可以让其他函数再不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象.
装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景.
二,装饰器的形成过程.
现在我又一个需求我想躺你测试这个函数的执行时间,在不改变这个函数代码的情况下:
import time def func1(): print('in func1') def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner func1 = timer(func1) func1()
但是如果有多个函数,我都想让你测试他们的执行时间,你每次是不是都的func1=timer(func1)?
这样还是有点麻烦.因为这些函数的函数名可能是不相同,有func1,func2等等,
所以更简单的方法,python给你提供了,那就是语法糖
import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> func1 = timer(func1) def func1(): print('in func1') func1()
刚刚我们讨论的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办?
def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner @timer def func1(a): print(a) func1(1)
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func1 = timer(func1) def func1(a,b): print('in func1') @timer #==> func2 = timer(func2) def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over' func1('aaaaaa','bbbbbb') print(func2('aaaaaa'))
上面的装饰器已经非常完美了,但是我们正常情况下查看函数信息的方法在此处都会丢失效果:
def index(): '''这是一个主页信息''' print('from index') print(index.__doc__) #查看函数注释的方法 print(index.__name__) #查看函数名的方法
如何解决呢?
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper @deco def index(): '''哈哈哈哈''' print('from index') print(index.__doc__) print(index.__name__)
三,开放封闭原则.
1.对扩展是开放的
为什么要对扩展开放呢?
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何
更信和修改.所以我们必须允许代码扩展,添加新功能.
2.对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给他人舒勇了,
如果这个时候我们对其进行修改,很有可能影响其他已经在使用的该函数的用户.
装饰器完美的遵循的这个开放封闭原则.
四.装饰器的主要功能个固定结构.
def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
五.带参数的装饰器.
假如你有成千上万个函数使用一个装饰器,现在你想把这些装饰器都取消掉,你要怎么做?
一个一个取消掉?,没日没夜忙活3天...
过两天你领导想通了再让你加上...
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函数之前要做的''') re = func(*args,**kwargs) if flag: print('''执行函数之后要做的''') return re return inner return timer @outer(False) def func(): print(111) func()
六,多个装饰器装饰一个函数.
def wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper2 @wrapper1 def f(): print('in f') f()