• Python装饰器的诞生过程-->和闭包的微妙关系


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

    一、函数特性

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

    1. 函数作为变量传递

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

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

     

    2.函数作为参数传递

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

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

     

    3.函数作为返回值

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

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

     

    4.函数嵌套及跨域访问

    def outer():
        x = 1
        def innner():
            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中装饰器的诞生过程。

     

     

     

    注:本文转自Python中文社区 作者ChrisYZX

  • 相关阅读:
    java中i++ 和 ++i的区别
    下载及配置Python+openCV
    Java 计算两个日期相差多少年月日
    conda创建、查看、删除虚拟环境
    MySQL Explain详解
    mysql实现group by后取各分组的最新一条
    Mybatis中的映射结果resutType和resultMap
    java8 Stream 快速实现List转map 、分组、过滤等操作
    LC1263-AI寻路优化: 距离优先bfs -> heuristic + A* -> tarjan + A*
    第8章复习
  • 原文地址:https://www.cnblogs.com/babyjoy/p/9439586.html
Copyright © 2020-2023  润新知