装饰器执行的原理顺序

tech2024-08-16  65

装饰器执行的原理/顺序

装饰器的顺序装饰器的执行原理装饰器函数:被装饰器装饰的函数:调用被装饰器装饰函数的过程: 多个装饰器装饰函数时的执行过程第一步:输出语句----第二个装饰器封装----第二步:输出语句----第一个装饰器封装----第三步:输出语句开始调用函数test第四步:输出语句----第一个装饰器执行----第五步:输出语句----第二个装饰器执行----第六步:输出语句----被装饰的函数开始执行----第七步:输出语句<第一个><第二个>hello python decorator,1+3=4

装饰器的顺序

多个装饰器装饰函数时,离函数近的装饰器先进行装饰,下面的装饰器先装饰完后将整个装饰结果给第一个装饰器进行装饰

即:封装时自内而外(自下而上),执行时自外而内(自上而下)

例子可以参考这篇文章

装饰器的执行原理

以代码为例:

##定义装饰器 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的装饰,实现了权限验证功能。

多个装饰器装饰函数时的执行过程

#####定义第一个装饰器 def first(fun): print('----第一个装饰器封装----') def inner1(*args,**kwargs): print('----第一个装饰器执行----') return '<第一个>' + fun(*args,**kwargs) + '</第一个>' return inner1 #####定义第二个装饰器 def second(fun): print('----第二个装饰器封装----') def inner2(*args,**kwargs): print('----第二个装饰器执行----') return '<第二个>' + fun(*args,**kwargs) + '</第二个>' return inner2 #####装饰器去装饰函数 @first @second def test(a,b): print('----被装饰的函数开始执行----') return f'hello python decorator,{a}+{b}={a+b}' print("开始调用函数test") ret = test(1,3) print(ret)

运行结果为:

可以看到,多个装饰器去装饰同一个函数的时候,最里面的装饰器是最开始进行装饰的。

执行步骤:

第一步:输出语句----第二个装饰器封装----

用@second装饰器去对函数test进行装饰,因此会先去执行second函数,因为此时还没有调用test函数,所以不会执行second函数里面的inner2函数,所以就输出了“----第二个装饰器封装----“语句,并且返回inner2的引用,所以此时就是second(test)函数。

第二步:输出语句----第一个装饰器封装----

该函数又被@first函数装饰,因此就先去执行first函数,因为此时还没有调用test函数,所以不会执行first函数里面的inner1函数,所以就输出了“----第一个装饰器封装----“语句,并且返回inner1的引用,所以此时就是first(second(test))函数。

所以前1,2步就是进行函数的封装。

第三步:输出语句开始调用函数test

函数装饰完毕之后,就执行到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,再将前面返回的内容一层层组合,所以最终的返回值是<第一个><第二个>hello python decorator,1+3=4</第二个></第一个>

最新回复(0)