• python装饰器的实现


    说起装饰器我们可能已经很熟悉了(不了解的可以查看python基础学习——装饰器),随手就可以写一个简单的装饰器

    
    def decorator(func):
        def inner(*args, **kwargs):
            # 执行函数前做点事
            result = func(*args, **kwargs)
            # 执行函数后干点啥
            return result
        return inner
    

    但是装饰器的实现可不是只有这一种,请看下面

    通过类来实现

    上面写的装饰器是由函数的方式实现的,但我们也可以用类的方式写一个同样的装饰器,还记得call方法吗

    
    class decorator:
        def __init__(self,func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            # 执行函数前做点事
            result = self.func(*args, **kwargs)
            # 执行函数后干点啥
            return result
    

    比如有一个add()函数被装饰,其实相当于add = decorator(add),那么decorator(add)就是这个类的实例, 执行add(a,b)的时候就是执行call方法了

    参数化的装饰器

    在装饰器中,我们在被装饰函数执行前会做一些事,在被装饰函数执行后可能也会做一些事,可是按照上面的写法,这些事情都是固定写好的,可不可以让这些动作会自定义的做些区别变化,那么参数化的装饰器能够满足这个要求

    
    def decorator(what_i_say='我什么也没说'):
        def actual_decorator(func):
            def inner(*args, **kwargs):
                # 执行函数前做点事
                print(what_i_say)
                result = func(*args, **kwargs)
                # 执行函数后干点啥
                return result
            return inner
        return actual_decorator
    
    @decorator('我要做一次加法')
    def add(a, b):
        return a + b
    
    print(add(3, 9))
    

    有了这个参数化装饰器,我们就可以在装饰函数时将参数写在括号内,也就是传入参数(这里我传的是字符串,其实没啥意义,只是为了简单表示参数)

    但是我们看到这个装饰器的实现中出现了三次def,之前的不都是出现两次吗,这次怎么出现了3次?它是怎么执行的

    其实稍微想一下就想通了,还是按照装饰的过程来

    之前是add = decorator(add),这次就把decorator换成decorator(‘我要做一次加法’),add = decorator(‘我要做一次加法’)(add),由于函数是一等对象,所以decorator(‘我要做一次加法’)就是装饰器中第一次返回的actual_decorator,由于闭包的特性,传递的参数绑定到了内部函数中,所以decorator执行完后,传入的’我要做一次加法’还是可以打印出来。

    所以这个参数化的装饰器和普通的装饰器装饰的过程是一样的。

    保存函数元数据的装饰器

    在使用装饰器后一段时间,可能有一天我们会突然发现一点不对劲的地方,比如我们打印被装饰的函数的时候

    
    print(add)
    #<function decorator.<locals>.actual_decorator.<locals>.inner at 0x00000211E632CB70>
    

    咦,不对啊,怎么它的名字不是add而是decorator..actual_decorator..inner这个玩意。我们仔细一读想起来了,这是被装饰器装饰了的那个函数,所以它把装饰器里的那个给打印出来了。可是把这个玩意打印出来干嘛呀,我要原来的函数名,有没有什么办法啊,办法当然有,如下

    
    from functools import wraps
    
    def decorator(what_i_say):
        def actual_decorator(func):
    
            @wraps(func)
            def inner(*args, **kwargs):
                # 执行函数前做点事
                print(what_i_say)
                result = func(*args, **kwargs)
                # 执行函数后干点啥
                return result
            return inner
        return actual_decorator
    

    我们从functools模块中引入了wraps()装饰器,用它来装饰装饰器中的inner函数,这样再次使用这个装饰器去装饰函数,它的元数据就保留下来了

    
    @decorator('我要做一次加法')
    def add(a, b):
        return a + b
    
    print(add)
    
    # <function add at 0x000001F5DEE966A8>
    
  • 相关阅读:
    网络世界中的图片以及相关的处理
    Ninject 2.x细说1.基本使用
    Orchard1.4新功能自动路由(AutoRouter)并附Orchard最新1.4版汉化包
    json的一点总结
    ASP.NET MVC路由扩展:路由映射
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(12) 网络相关操作辅助类
    IIS是如何处理ASP.NET请求的
    一周最新示例代码回顾 (3/19–3/25)
    .NET插件系统(三) 插件间通信问题——设计可自组织和注入的组装程序
    缓存总结
  • 原文地址:https://www.cnblogs.com/sfencs-hcy/p/10111508.html
Copyright © 2020-2023  润新知