zoukankan      html  css  js  c++  java
  • python的带参装饰器

    又是从做铺垫开始: 

    *文档字符串(Documentation Strings)

    def add(x, y):
         """This is a function for add"""  # 函数语块第一句;一般用三引号(因为习惯是多行的文本);可以使用.__doc__访问;惯例是首写是大写字母;
         return x+y
    
    print("name={}
    doc={}".format(add.__name__, add.__doc__))  
    # 打印出:
    add(x, y)
    doc=This is a function of addition

      

    在装饰器调用过程中,我们打印出这些函数属性信息会发现问题:

    def logger(fn):
         def wrapper(*args, **kwargs):
              """I am wrapper"""
              print('begin')
              x = fn(*args, **kwargs)
              print('end')
              return x
         return wrapper
    
    @logger  # add = logger(add)
    def add(x, y):
         """This is a function for add"""
         return x+y
    
    print("name={}
    doc={}".format(add.__name__, add.__doc__))
    # 打印出:
    name=wrapper
    doc=I am wrapper

    我们打印出的add()函数的属性并不是add()函数定义时的属性信息,而是wrapper()函数里的属性信息。(因为@logger里将add重新赋值为wrapper)

     原函数对象的属性都被替换了,而使用装饰器,我们的需求是查看被封装函数的属性。怎么解决这个矛盾? ----> 提供一个函数,将被装饰函数的属性拷贝到装饰函数的属性内。
    # 将原函数的__name__,__doc__属性赋值到新函数的属性值内
    def copy_properties(src, dst):
        dst.__name__ = src.__name__
        dst.__doc__ = src.__doc__
      
    def logger(fn):
         def wrapper(*args, **kwargs):
              """I am wrapper"""
              print('begin')
              x = fn(*args, **kwargs)
              print('end')
              return x
        copy_properties(fn, wrapper)
         return wrapper
    
    @logger  # add = logger(add)
    def add(x, y):
         """This is a function for add"""
         return x+y
    
    print("name={}
    doc={}".format(add.__name__, add.__doc__))
    # 打印出:
    name=add
    doc=This is a function for add

    通过copy_properties()函数,将被装饰函数的属性赋值给装饰函数。在刚了解完装饰器是对原函数起着增加其额外的功能的作用之后,我们是不是会想到这个copy_properties()函数也可以改造成一个装饰

    器?

    copy_properties()函数 --柯里化--> 加上语法糖形成装饰器

    柯里化:

    # copy_properties柯里化
    def copy_properties(src):
        def _copy(dst):
            dst.__name__ = src.__name__
            dst.__doc = src.__doc__
            return dst
        return _copy
    
    # 被装饰的logger函数
    def logger(fn):
         def wrapper(*args, **kwargs):
              """I am wrapper"""
              print('begin')
              x = fn(*args, **kwargs)
              print('end')
              return x
         copy_propertites(fn)(wrapper)  # 柯里化后copy_propertites的调用
         return wrapper
    
    # 调用
    @logger  # add = logger(add)
    def add(x, y):
         """This is a function for add"""
         return x+y
    
    print("name={}
    doc={}".format(add.__name__, add.__doc__))
    # 打印出
    name=add
    doc=This is a function for add

     可以看见这里的柯里化会有些许不同的地方,之前是logger(fn)(*args, **kwargs),现在是copy_properties(fn)(wrapper)。之前是传入函数和函数的参数,现在是分别传入两个函数。

    于是就形成了特殊的带参装饰器

    # copy_properties柯里化
    def copy_properties(src):
        def _copy(dst):
            dst.__name__ = src.__name__
            dst.__doc = src.__doc__
            return dst
        return _copy
    
    # 被装饰的logger函数
    def logger(fn):
        @copy_properties(fn) => copy_propertites(fn)(wrapper)  # 带参装饰器
         def wrapper(*args, **kwargs):
              """I am wrapper"""
              print('begin')
              x = fn(*args, **kwargs)
              print('end')
              return x
         return wrapper
    
    # 调用
    @logger  # add = logger(add)
    def add(x, y):
         """This is a function for add"""
         return x+y
    
    print("name={}
    doc={}".format(add.__name__, add.__doc__))
    # 打印出
    name=add
    doc=This is a function for add

     根据以上归纳总结带参装饰器的特点

    它是一个函数(copy_properties),

    函数作为它的形参(fn),

    返回值是一个不带参的装饰器函数(wrapper),

    使用@function_name(参数列表)语法糖方式调用(@copy_properties(fn))。

    可以看作在装饰器外层又加了一层函数。

    上述的利用带参装饰器保持被装饰函数的属性不变,在python中functools模块就是这样处理的。有兴趣的可以详细了解一下functools模块。

  • 相关阅读:
    异常定义-Mybatis中的源码参考
    前置机介绍说明
    MyBatis源码解析(一)
    Mybatis思
    石杉的架构笔记(一)
    nacos启动
    JVM图解
    二叉搜索树的第K大节点
    第一个只出现一次的字符
    表示数值的字符串
  • 原文地址:https://www.cnblogs.com/hongdanni/p/10469712.html
Copyright © 2011-2022 走看看