• 多个装饰器修饰一个函数


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

    多个装饰器修饰一个函数

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

    先看代码

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述
    可以看到装饰的时候 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):
    
    • 1
    • 2

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

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

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

  • 相关阅读:
    关于Java CyclicBarrier reset的理解
    前端数据可视化:ECharts使用
    unique_ptr的大小探讨
    数据库安全-分布式数据库-数据仓库技术-反规范化技术-大数据
    并发与并行,线程的创建
    视觉slam14讲 ——ch2实践部分
    R语言绘制环状柱状堆积图+分组+显著性
    Docker---Docker-compose部署安装Prometheus+Alertmanager+Grafana
    软件工程毕业设计课题(65)微信小程序毕业设计PHP食堂餐厅预约订座小程序系统设计与实现
    K8S -----二进制搭建 Kubernetes v1.20
  • 原文地址:https://blog.csdn.net/qq_26826585/article/details/126453117