多个装饰器修饰一个函数

对多个装饰器一个装饰器的修饰顺序有疑问,于是写了个测试用例测试了下,发现了一些有意思的事情,刚开始不明白,经过思考后有所悟,遂记下

多个装饰器修饰一个函数

首先先说结论:多个装饰器装饰一个函数的时候,装饰的时候是从下往上装饰(由内往外),执行的时候从上往下执行(由外往内)。

先看代码

def desc1(func):
    def inner1(*args,**kwargs):
        print('desc1')
        func(*args,**kwargs)
    return inner1
    
def desc2(func):
    def inner2(*args,**kwargs):
        print('desc2')
        func(*args,**kwargs)
    return inner2

@desc1 #
@desc2 #add=inner2(会携带打印desc2)
def add(x,y):
    print(x+y)

add(1,2)

在这里插入图片描述
可以看到装饰的时候 desc2先装饰 add 函数,接着作为一个整体,被 desc1 装饰。执行的时候,由外往内,依次执行 desc1desc2 的装饰(添加的打印语句),最后执行函数本身。

一点有意思的事

看到两个装饰器中都执行了 func(*args,**kwargs),本能的反应是最终会2次执行函数,也就是打印两个3。然后我分别删除了 desc1desc2 中的 func 函数,得到的结果如下:

删除 desc1func 函数
删除 desc1 的 func 函数

删除 desc2func 函数
在这里插入图片描述

这是怎么回事,删除 desc1funcdesc2 竟然还不能装饰了?

仔细思考后,原来是这样的:

装饰器的作用就是在不修改原函数不影响原函数的功能的基础上,给函数增加额外的功能。

首先说一下装饰器是如何给原函数增加功能的
装饰器 装饰一个函数也就是写到函数上方 @desc2,这种语法糖的写法等价于 add = desc(func)。也就是把被修饰的函数当作参数传递到了装饰器中,而装饰器返回内部函数 inner2,于是 add=inner2,再执行 add 的时候就是执行 inner2 函数,这时候可以在 inner2 中增加额外的功能比如增加打印信息,完了在原函数执行本身,从而达到了给原函数增加功能的目的。

再看一下如何理解以上输出结果
装饰器返回内部函数 inner2 的时候,可以认为是给原函数 add 携带了 print('desc2') 这种特质,他和原函数 func(*args,**kwargs) 整体作为一个函数,被 desc1 修饰,而 desc1 也是包装了一个 print('desc1')+func(*args,**kwargs) 的形式,这个 func(*args,**kwargs) 被 内部的 刚刚那个 print('desc2')+func(*args,**kwargs) 占据,画成图形来理解的话就像是这样
在这里插入图片描述
于是执行 add 的时候先执行 print('desc1'),接着执行内部的 func 函数,而 func 函数实际就是

@desc2
def add(x,y):

于是执行 print('desc2'),最后执行 内部的 add 函数。这样,就只会执行一次原函数。

那么为什么删除 desc1func 就只输出 'desc1' 呢?
删除 desc1func 就相当于删除了 desc1 装饰器的 func 盒子,相当于删除了被 desc2 修饰的函数整体,自然不能执行 desc2 修饰的函数了

为什么删除 desc2func 就只输出 'desc1''desc2' 呢?
删除 desc2func 就相当于删除了 desc2func 盒子,desc2func 盒子中装的是原函数 add,自然不会输出 add 的运行结果了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你不是叶秋

你的鼓励就是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值