多个装饰器装饰函数时,离函数近的装饰器先进行装饰,下面的装饰器先装饰完后将整个装饰结果给第一个装饰器进行装饰
即:封装时自内而外(自下而上),执行时自外而内(自上而下)
例子可以参考这篇文章
以代码为例:
##定义装饰器 def check(func): print("验证权限") def inner(identify): func(identify) return inner ###装饰装饰器 @check def f1(user_id): if user_id=="root": print("允许root用户操作") else: print(f"不允许{user_id}用户操作") f1("root")流程如下:
这里的装饰器函数是check,check函数接收一个参数func,其实就是接收一个函数的名字,check函数内部又定义了一个函数inner,在inner函数中增加权限校验,并在验证完权限后调用传进来的参数func,同时check的返回值为内部函数inner,其实就是一个闭包函数。
在函数f1上增加@check,其实就是给f1函数额外的增加了权限验证的输出语句。当python解释器执行到这条语句的时候,会去调用check函数,同时将被装饰的函数名作为参数传入(此时为f1),根据闭包分析,在执行check函数的时候,返回值是inner函数,同时把返回值inner赋值给f1函数(这里其实传递的是函数的引用),此时的f1已经不是未加装饰时的f1了,即f1函数已经改变了,不再是原来的内容了,而是指向了check.inner函数的地址。
在调用f1(“root”)的时候,其实调用的是check.inner函数,那么此时就会先执行权限验证,然后再调用原来的f1(“root”),该处的f1就是通过装饰传进来的参数f1。
从而,就完成了对函数f1的装饰,实现了权限验证功能。
运行结果为:
可以看到,多个装饰器去装饰同一个函数的时候,最里面的装饰器是最开始进行装饰的。
执行步骤:
用@second装饰器去对函数test进行装饰,因此会先去执行second函数,因为此时还没有调用test函数,所以不会执行second函数里面的inner2函数,所以就输出了“----第二个装饰器封装----“语句,并且返回inner2的引用,所以此时就是second(test)函数。
该函数又被@first函数装饰,因此就先去执行first函数,因为此时还没有调用test函数,所以不会执行first函数里面的inner1函数,所以就输出了“----第一个装饰器封装----“语句,并且返回inner1的引用,所以此时就是first(second(test))函数。
所以前1,2步就是进行函数的封装。
函数装饰完毕之后,就执行到print(“开始调用函数test”)语句了,输出“开始调用函数test”
调用函数test(1,3),此时的函数不再是原来的test了,而是经过装饰器装饰的函数了,此时的函数是first(second(test))。因为返回的是inner1函数的引用,所以会先去执行inner1函数,输出“第一个装饰器执行“,然后返回<第一个>+inner2的引用+</第一个>。
接着去执行inner2的引用,所以就会输出语句“第二个装饰器执行”,并且返回<第二个>+test的引用+</第二个>。
接着去执行test的引用,此时就真正的调用函数test了,所以会输出语句“----被装饰的函数开始执行----”
然后返回hello python decorator,1+3=4,再将前面返回的内容一层层组合,所以最终的返回值是<第一个><第二个>hello python decorator,1+3=4</第二个></第一个>