Python中的装饰器是通过利用了函数特性的闭包实现的,所以在讲装饰器之前,我们需要先了解函数特性,以及闭包是怎么利用了函数特性的

① 函数特性

Python中的函数特性总的来说有以下四点:

1. 函数作为变量传递

def add(x):
    return x + 1
a = add                    # 作为变量

说明:函数如果不加括号,是不会执行的,代表的是一个函数对象,它是可以作为变量来传递

2. 函数作为参数传递

def add(x):
    return x + 1
def execute(f):
    return f(3)
execute(add)                # 作为参数

说明:一个函数可以接受另一个函数对象作为自己的参数,并对函数对象进行处理

3. 函数作为返回值

def add(x):
    return x + 1

def get_add():
    return add             # 作为返回值

说明:一个函数的返回值可以是另一个函数对象

4. 函数嵌套及跨域访问

def outer():
    x = 1
    def inner():
        print(x)         # 被嵌套函数inner内部的x变量可以到封装域去获取
    inner()

outer()

说明:一个函数(主函数)内部是可以嵌套另一个函数(子函数)的,比如outer函数从内部嵌套了inner。
一个函数本地域没有的变量,是可以跨到它的封装域(主函数与子函数之间的范围)去寻找的

② 闭包的实现

python中的装饰器是通过闭包实现的,简单地讲,闭包就是引用了外部变量的内部函数,而闭包的实现正是利用了以上函数特性,下面我们来看看闭包是如何实现的:

def outer(x):
    def inner():                  # 函数嵌套
        return x                  # 跨域访问,引用了外部变量x

    return inner                  # 函数作为返回值

closure = outer('外部变量')        # 函数作为变量赋给closure
print(closure())                  # 执行闭包

执行结果:

外部变量

说明:我们分析下这个流程,outer接收到'外部变量',传给inner,作为它return的参数,最后outer返回inner函数,返回的inner函数作为变量传递给closure,最后执行closure这个函数对象,实际上是执行了inner这个函数,返回了 '外部变量',这样就实现了一个简单的闭包

我们发现上面的闭包例子只用到了之前说的其中3个函数特性,函数作为参数 这个特性好像并没用上,别急,我们一步步来,试想一下,outer的参数x是不是也可以是一个函数对象?

下面我们来改写一下实现闭包的代码:

def func():
    return '函数func'

def outer(x):
    def inner():                              # 函数嵌套
        return '戴了inner牌帽子的 ' + x()       # 跨域访问,引用了外部变量x

    return inner                              # 函数作为返回值

closure = outer(func)                         # 函数func作为outer的参数;函数作为变量赋给closure

print(func())                                 # 执行原始函数
print(closure())                              # 执行闭包

执行结果:

函数func
戴了inner牌帽子的 函数func

说明:我们看到打印的结果, 从 func() 到 closure(),我们是不是感觉函数func被装饰了一番,变成了closure,具体是怎么装饰的呢?

划重点来了!!!!!!!!!!!

我们看到closure实际上是outer(func),func作为参数传进outer,outer的子函数inner对func返回的结果进行了一番装饰,返回了一个装饰后的结果,最后outer返回inner,可以说inner就是装饰后的func,这就是一个函数被装饰的过程,重点在于执行 outer(func) 这个步骤

③ 装饰器语法糖 @

python给我们提供了语法糖 @,我们想执行 outer(func) 的时候,只需要把outer函数@到func函数的上面就可以了

具体实现如下:

def outer(x):
    def inner():
        return '戴了inner牌帽子的 ' + x()

    return inner

@outer
def func():
    return '函数func'

print(func())

执行结果:

戴了inner牌帽子的 函数func

说明:我们看到打印的结果跟我们执行closure()的结果是一样的,也就说明 加了outer装饰器的func 等价于 outer(func),所以我们很清楚地知道装饰器@的作用是什么了,就是拿来把被装饰的函数作为参数传递到装饰器函数里面加工的,最后执行被装饰函数的时候,就相当于执行了一个加工后的函数。

以上就是Python中装饰器的诞全生过程……

作者:ChrisYZX
链接:

https://www.jianshu.com/p/422a01f8532b
來源:简书

-END-


识别图中二维码,领取python全套视频资料

Python 装饰器的诞生过程的更多相关文章

  1. Python装饰器的调用过程

    在Python学习的过程中,装饰器是比较难理解的一个应用.本人也在学习期间也遇到很多坑,现将装饰器的基本调用过程总结一下. 首先,装饰器用到了“闭包”,而“闭包”是学习装饰器的基础,所以在讲装饰器之前 ...

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

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

  3. Python装饰器由浅入深

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

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

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

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

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

  6. 初识Python装饰器

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

  7. 自创最精简的python装饰器

    个人心血原创,欢迎转载,请注明作者和出处.否则依法追究法律责任!!!! author:headsen  chen date:2018-03-21  10:37:52 代码: 代码解析过程:1,def ...

  8. python 装饰器 一篇就能讲清楚

    装饰器一直是我们学习python难以理解并且纠结的问题,想要弄明白装饰器,必须理解一下函数式编程概念,并且对python中函数调用语法中的特性有所了解,使用装饰器非常简单,但是写装饰器却很复杂.为了讲 ...

  9. 如何理解Python装饰器

    如何理解Python装饰器?很多学员对此都有疑问,那么上海尚学堂python培训这篇文章就给予答复. 一.预备知识 首先要理解装饰器,首先要先理解在 Python 中很重要的一个概念就是:“函数是 F ...

随机推荐

  1. 为什么对一些矩阵做PCA得到的矩阵少一行?

    很多时候会出现把一个N*M的矩阵做pca(对M降维)之后却得到一个M*(M-1)矩阵这样的结果.之前都是数学推导得到这个结论,但是, 今天看到一个很形象的解释: Consider what PCA d ...

  2. VB.NET & 策略模式(下机用户类型选择)

    上篇文章讲述了对于下机操作和基本数据设定的时间联系,今天主要就是应用"策略模式"来了解了解对于固定用户,以及暂时用户之间的选择,看学习设计模式的时候自己对于策略模式的理解,我们能够 ...

  3. KMP算法完整教程 (上)

    KMP算法完整教程 全称: Knuth_Morris_Pratt Algorithm(KMP算法) 类型: 高级检索算法 功能: 字符串匹配查找 提出者: D.E.Knuth(克努兹),J.H.Mor ...

  4. EasyUI DataGrid合并单元

    <table id="tt"></table> $('#tt').datagrid({     title:'Merge Cells',     iconC ...

  5. php -- 魔术方法 之 自动加载:__autoload()

    自动加载类 背景: 很多开发者写面向对象的应用程序时对每个类的定义建立一个 PHP 源文件.一个很大的烦恼是不得不在每个脚本开头写一个长长的包含文件列表(每个类一个文件). 在 PHP 5 中,不再需 ...

  6. LoadRunner Error code 10053,Software caused connection abort

    发现问题的应用场景  C/S结构程序,请求响应采用异步机制.即客户端发送一个请求后不是一直等待这个结果,客户端将请求存放在请求队列并获得一个JOBID,服务器运行后将运行结果存放在响应队列,客户端定时 ...

  7. HttpModule,HttpContext,HttpHandler

    http://www.cnblogs.com/wujy/tag/ASP.NET%E5%9F%BA%E7%A1%80/ http://www.th7.cn/Program/net/2011/12/26/ ...

  8. nginx 服务器重启命令,关闭(转)

    nginx -s reload  :修改配置后重新加载生效 nginx -s reopen  :重新打开日志文件nginx -t -c /path/to/nginx.conf 测试nginx配置文件是 ...

  9. open() 函数以 a+ 模式打开文件

    这种模式打开文件,可读可写,从文件顶部读取内容,从文件底部追加内容,文件不存在则自动创建 [root@localhost ~]$ cat 1.txt aaa bbb ccc In [1]: data ...

  10. C语言字符串的输入输出

    字符串的输出 在C语言中,输出字符串的函数有两个: puts():直接输出字符串,并且只能输出字符串. printf():通过格式控制符 %s 输出字符串.除了字符串,printf() 还能输出其他类 ...