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就是一个闭包。

Python装饰器的调用过程的更多相关文章

  1. Python 装饰器的诞生过程

    ​ Python中的装饰器是通过利用了函数特性的闭包实现的,所以在讲装饰器之前,我们需要先了解函数特性,以及闭包是怎么利用了函数特性的 ① 函数特性 Python中的函数特性总的来说有以下四点: 1. ...

  2. 初识Python装饰器

    python中,一切皆对象.做为面向对象开发中非常重要的一个环节,函数有着无可替代的作用. 函数可以作为对象赋值给一个变量,可以作为元素添加到集合对象中,可以作为参数值传递给其它函数,还可以当做函数的 ...

  3. python装饰器 & flask 通过装饰器 实现 单点登录验证

    首先介绍装饰器,以下是一段标注了特殊输出的代码.用于帮助理解装饰器的调用过程. import time def Decorator_one(arg1): info = "\033[1;31; ...

  4. Python使用装饰器自动调用父类__init__

    众所周知,Python中class的构造函数实际是__new__(),但是如果我们执行p1=Point()的时候,不仅会调用Point的__new__方法,而且会调用Point的__init__方法. ...

  5. python 多个装饰器的调用顺序

    python 多个装饰器的调用顺序 一般情况下,在函数中可以使用一个装饰器,但是有时也会有两个或两个以上的装饰器.多个装饰器装饰的顺序是从里到外(就近原则),而调用的顺序是从外到里(就远原则). 原代 ...

  6. python装饰器通俗易懂的解释!

    1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...

  7. Python装饰器由浅入深

    装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...

  8. python 装饰器、内部函数、闭包简单理解

    python内部函数.闭包共同之处在于都是以函数作为参数传递到函数,不同之处在于返回与调用有所区别. 1.python内部函数 python内部函数示例: def test(*args): def a ...

  9. 一篇关于Python装饰器的博文

    这是一篇关于python装饰器的博文 在学习python的过程中处处受阻,之前的学习中Python的装饰器学习了好几遍也没能真正的弄懂.这一次抓住视频猛啃了一波,就连python大佬讲解装饰器起来也需 ...

随机推荐

  1. easyui 如何为标签动态追加属性实现渲染效果

    简述一下在项目遇到的问题,这边有一个需求,选择不同类型,加载不同的div标签(其中属性是否必填是区分类型的关键) html界面是这样的 <div class="grid_1 lbl&q ...

  2. Quartz的基本使用之入门(2.3.0版本)

    一.Quartz可以用来做什么 Quartz是一个强大任务调度框架,我工作时候会在这些情况下使用到quartz框架,当然还有很多的应用场景,在这里只列举2个实际用到的 餐厅系统会在每周四晚上的22点自 ...

  3. 浅谈对象的两个方法:Object.keys() ,Object.assign();

    1 : Object.keys(obj) 返回给定对象的所有可枚举属性的字符串数组 例子1: var arr = [1, 2, 6, 20, 1]; console.log(Object.keys(a ...

  4. java输入最大10位数,倒数输出(很鸡肋)

    public class D { public static void main(String[] args) { System.out.println("请输入数字(最大十位数):&quo ...

  5. JQ 向上查找指定 同辈元素 找到后返回

    由于JQ 只有 prev() 和 prevAll() prev()只能找一个 prevAll()把所有的都给找了 我想要的是: 在同辈元素中向上找,直到找到 我指定的元素 后,返回他. 所以自己写了个 ...

  6. 【阅读笔记】《C程序员 从校园到职场》第八章 算法和协议(Part 2)

    原文链接: 让你提前认识软件开发(19):C语言中的协议及单元测试示例 CSDN博客 https://blog.csdn.net/zhouzhaoxiong1227/article/details/2 ...

  7. resful

    一个完整的node resful api 一个更完整的项目 介绍

  8. useradd语法2

    在Linux中 useradd 命令用来创建或更新用户信息. useradd 命令属于比较难用的命令 (low level utility for adding users),所以 Debian 系的 ...

  9. JS查看IOS手机的版本号

    微信弹portal连接wifi的开发过程中,遇到了有些版本的ios系统在弹portal的浏览器(以下称小浏览器)中无法进行alert(),weixin://等等操作,只能使用window.locati ...

  10. Map、Set、List集合差别及联系详解

    提到集合之前,先说说数组Array和集合的区别:   (1)数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型)   (2)JAVA集合可以存储和操作数目不固定的一组数据. ( ...