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