释义
装饰,即添加额外的修饰,在不改变函数源代码和调用方式的前提下,添加额外的功能。器,在python里面,指定的函数,例如迭代器,生成器,都是函数。装饰器,本质就是函数,功能是为其他函数添加新功能。推荐文章:https://segmentfault.com/a/1190000007837364
装饰器遵循的原则(开放封闭原则)
1.不改变被修饰函数的源代码
2.不改变被修饰函数的调用方式
实现装饰器的原理构成
装饰器=高级函数+函数嵌套+闭包
实现装饰器
例子1:
import datetime
import time
def count1(a,delta): #附加count1函数
if delta < a:
print(delta)
else:
print("hhhhhh")
def logger2(a=5,fun=count1): #方便为count1函数传参
def logger1(fn):
def inner(*args,**kwargs):
"""what fuck"""
print("gogogo")
start = datetime.datetime.now()
ret = fn(*args,**kwargs) #调用主体函数
delta = (datetime.datetime.now()-start).total_seconds()
fun(a,delta)
return ret
return inner
return logger1
@logger2(1) #add3 = logger1(add3) #语法糖:@
def add3(x,y): #主体函数
return x+y
print(add3(2,5))
打印结果:
gogogo
0.0
7
例子2:
def wrapper1(func):
def inner():
print ('w1,before')
func()
print('w1,after')
return inner
def wrapper2(func):
def inner():
print('w2,before')
func()
print('w2,after')
return inner
@wrapper2 #连着两个装饰器,相当于foo = wrapper2(wrapper1(foo))
@wrapper1
def foo():
print ('foo')
print(foo())
传参***解密
def Before(request): #1 #15
print('before') #16
def After(request): #2 #23
print('after') #24
def Filter(before_func,after_func): #3 #5
def outer(main_func): #6 #8
def wrapper(request): #9 #13
before_result =before_func(request) #14
if(before_result !=None): #17
return before_result
main_result = main_func(request) #18
if(main_result !=None): #21
return main_result
after_result = after_func(request) #22
if(after_result !=None): #25
return after_result
return wrapper #10
return outer #7
@Filter(Before,After) #4
def Index(request): #11 #19
print('index') #20
Index('example') #12
首先是在第3
步这里,解释器发现了这个函数,并把它放进了内存里,然后第4
步又读到了一个装饰器,它就从内存里找到装饰器的地址返回到了第5
步这个装饰器的位置。继续往下读,第6
步它又把发现了一个outer函数,于是把outer函数的地址放进了内存里,然后就停止了,因为它很清楚它不是来执行outer的,所以它调过了这个函数并顺序执行了这个函数外面的第一句话:第7
步,return outer。这个时候解释器发现这不就是刚刚记下了地址的那个方法么?它就又回来了之前的地址,找到了outer函数。。。就是这样,直到执行到第10
步return wrapper,这里我没有写,其实它也是兴冲冲的回到了家wrapper方法那里的,但是它发现下面已经没有它需要记录地址的函数了。所以它把最后的这个wrapper函数的地址返回给了装饰器,也就是装饰器下面的index方法。
这个时候,我们在程序中调用了这个index方法,那么解释器就把我们领到wrapper那里开始执行了,在wrapper里我们可以使用外层函数传过来的方法参数Before和After,这其实就是装饰器参数的秘密了。
附言
装饰器分两部,第一步执行装饰器函数,获取inner函数的标识,在C中就是指向函数的指针,在Python中也就是函数体内存空间的标识,这个标识指向函数体的地址。第二步就是进行更名,标识说换就换,函数体地址不变,只不过换了件衣服,自然不会影响结果。对于三层装饰器函数或者说是带参数的装饰器函数,可以看成装饰器结合的次序,就是先执行最外层的装饰器函数,传入参数,同时返回里层装饰器名。这里的参数可以是函数的标识,函数定义在外面,before_func和after_func就可以随心所欲,作为参数传入