随笔 - 231  文章 - 205  评论 - 20  阅读 - 41万

Python装饰器的调用过程

回到顶部

Python装饰器的调用过程

  在Python学习的过程中,装饰器是比较难理解的一个应用。本人也在学习期间也遇到很多坑,现将装饰器的基本调用过程总结一下。

  首先,装饰器用到了“闭包”,而“闭包”是学习装饰器的基础,所以在讲装饰器之前先将“闭包”的基本概念带大家一起回顾一下:

  现有如下函数:

def func():
    def func1():
        print('i\'m func1')
    return func1
if __name__ == '__main__':   f
= func()
  f()
  print('函数func1的内存地址为:',f)

  我们在函数func()内部定义了另外一个函数func1(),最终return的是func1的内存地址。 

  函数定义完后,在全局把func()赋值给变量f,此时f中拿到的是func1的内存地址,这时候你可以把f看成是func1,进行f()操作相当于调用func1(),所以上面代码的输出结果为:

 

  此时有些人可能会问:既然f相当于func1,那么为何不在全局中直接调用func1()呢?答案是不行~因为func1()是在全局的函数func()里面定义的,全局情况下只能调用func(),不可以直接调用func()里面的函数:

  这里我们可以看到:"func1 is not defined",因为在全局程序只能调用func(),是找不到func1()的,跟别提调用了。

  所以,我们要想在全局情况下调用“全局函数”内部定义的函数,就必须令该全局函数返回“内部函数”的内存地址,然后将该内存地址赋值给一个变量,通过调用这个变量来实现“全局调用内部函数”,而此时,这个“内部的函数”就称为“闭包”

  而上述例子中,函数func1就是一个闭包。

  理解了“闭包”的概念后我们再来看“装饰器”的调用过程:

不带参数的装饰器

  如上图:这里我们先定义了一个装饰器Dec(),而Dec函数里面的outer函数就是一个闭包。当我们在函数func2定义前加上@Dec时,这个语句相当于:func2 = Dec(func2)。也就是说,我们在进行不带参数的装饰器的调用时,相当于把下面的函数名当做参数传给了@后面的函数,@Dec也就相当于执行了Dec(func2)。后面就好理解了:Dec()函数返回了outer函数的内存地址,下面的func2()其实就调用了“闭包”outer(),进行了outer()函数里面的操作。

带参数的装饰器

  这里需要注意的是:如果要返回函数的话,带参数的装饰器就要写三层内嵌函数。

  带参数的装饰器的具体执行过程分为两步:首先执行Dec('QQ'),不管中间过程,Dec函数返回的是函数outer的内存地址,此时就变成了@outer,按照“不带参数的装饰器”的调用过程我们知道,此时outer将函数func2的名称当做是参数执行outer里面的函数inner()。另外我们还需要注意:现在inner里不仅有func2,还有Dec本身所携带的参数'QQ'。

  此外:打印出来的"i'm inner"是在判定if type == 'QQ'后直接执行的;而"i'm func2"是inner()函数执行“outer函数所带的参数”调用的结果,也就是说inner函数最后调用了“outer函数所带的参数”func并执行了它,换句话讲,inner就是一个闭包。

posted on   江湖乄夜雨  阅读(6074)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示