一、有参装饰器
# 区别于无参装饰器,有参装饰器,顾名思义,就是装饰器带有参数,首先我们来看无参装饰器 # 无参装饰器模板如下: # def outter(func): # def inner(*args, **kwargs): # '''函数调用前需要增加的功能''' # res = func(*args, **kwargs) # '''函数调用后需要增加的功能''' # return res # # return inner # # # def index(*args, **kwargs): # print(*args, **kwargs) # return '任巍峰大帅哥' # 此时,两层函数的形参都有着自己特定的功能,func用来接收函数名,(*args,**kwargs)用来接收被装饰函数的参数,那么如果装饰器中如果需要参数,怎么办 # 那么我们或许会说,我们只需要在outter(func,a,b,c),或者inner(a,b,c,*args,**kwargs)装饰器需要几个参数,我们传几个参数就行 # 是的,如果作为一个函数,我们嵌套的时候可以这样子做,但是作为一个装饰器,我们应该遵循函数装饰前后调用方式不变的原则,所以,我们将外层函数的返回值设置成内层函数的函数名, # 首先我们看一下无参装饰器是怎么实现调用方式不变得 # index = outter(index) #先调用outter函数,并将该函数的值赋予变量名index # index(1, 2) #index()>>>>>等价于outter函数返回值()>>>>等价于inner() # 方式一:如果我们采用(a,b,c,*args,**kwargs)这种方式为装饰器传参,那么我们在调用的时候,就必须采用 # index(a,b,c,*args,**kwargs)>>>>inner(a,b,c,*args,**kwargs),这与原来的调用方式明显不一样 # 作为装饰器,被装饰函数装饰前怎么调,装时候还是应该怎么调,所以排除方式一 #方式二:那么,如果是outter(func,a,b,c),这种呢,这种如果单纯的作为嵌套函数是可以的,但是,作为装饰器,我们是需要用的 # 我们总不能每次用之前加一行代码 index = outter(index,a,b,c) 吧,所以,我们用的是语法糖,@outter,而语法糖默认传的参数就index一个 # 综上所述,既然通过形参无法满足内部函数对参数的需求,那么就采用第二种传参方式,闭包,在函数外面在包一层函数,有参装饰器呼之欲出 # # # def auth(a,b,c): # def outter(func): # def inner(*args, **kwargs): # '''函数调用前需要增加的功能''' # res = func(*args, **kwargs) # '''函数调用后需要增加的功能''' # return res # # return inner # return outter # 至此,有参装饰器模板补充完整,以后内部需要多少个参数,都可以通过auth(a,b,c)的形参传入,故而,装饰器最多只有三层 # 那么调用的时候如何做到调用方式不变呢,首先看语法糖在无参的时候怎么操作 # @outter >>>>>>>>,这里,@outter,他内部的函数是默认将下边函数的名字当作参数传入outter函数,即>>>>index = outter(index) # def index(*args, **kwargs): # print(*args, **kwargs) # return '任巍峰大帅哥' # 那么,对于有参装饰器,我们只需要在他前边加一行代码:outer = auth(a,b,c)>>>>等价于outter函数 # 此处,有人会问,outter等价于函数outter函数不是多此一举吗,这是因为,outter函数是局部空间的,你在全局作用域中直接找outter是无法找到的,因此不是多次一举. # 综上所述,我直接在全局作用域给函数添加装饰器,@outter是不是就可以合并成一步,@auth(a,b,c), # 综上所述,有参函数模板如下 # def auth(a,b,c): # def outter(func): # def inner(*args, **kwargs): # '''函数调用前需要增加的功能''' # res = func(*args, **kwargs) # '''函数调用后需要增加的功能''' # return res # # return inner # return outter # 调用方式如下 # @auth(a,b,c) # def index(*args, **kwargs): # print(*args, **kwargs) # return '任巍峰大帅哥' # index()
二、多层语法糖
理解了有参装饰器,那么多层语法糖的理解就显得顺理成章,多层语法糖的语法赋值是从下而上的,内层小函数执行时是从上而下的,我们通过一个例题来理解:判断七句print执行顺序
def outter1(func1): print('加载了outter1') def wrapper1(*args, **kwargs): print('执行了wrapper1') res1 = func1(*args, **kwargs) return res1 return wrapper1 def outter2(func2): print('加载了outter2') def wrapper2(*args, **kwargs): print('执行了wrapper2') res2 = func2(*args, **kwargs) return res2 return wrapper2 def outter3(func3): print('加载了outter3') def wrapper3(*args, **kwargs): print('执行了wrapper3') res3 = func3(*args, **kwargs) return res3 return wrapper3 @outter1 @outter2 @outter3 def index(): print('from index') index()
运行结果如下:
加载了outter3
加载了outter2
加载了outter1
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index