装饰器执行的原理/顺序

装饰器的顺序

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

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

例子可以参考这篇文章

装饰器的执行原理

以代码为例:

##定义装饰器
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</第二个></第一个>

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值