• python3 如何给装饰器传递参数


    引子

      之前写过一篇文章用来讲解装饰器(https://www.cnblogs.com/JiangLe/p/9309330.html) 、那篇文章的定位是入门级的

      所以也就没有讲过多的高级主题,决定在这里讲一下如果为装饰器传递参数

    目标

      我们有两个函数“add_fun”、“add” 其中“add_fun”已经过时、如果用户有调用这个函数的话就提示它“add_fun”已经过时并且引导

      它去调用“add”函数

    addadd_fun函数的定义

    def add_fun(x,y):
        """
        实现两个数相加、并返回合
        """
        return x+y
    
    
    def add(x,y):
        """
        实现两个数相加、并返回合
        """
        return x+y  

    通过装饰器引导调用add_fun的用户去调用add

    def deprecated(fun,new_fun_name):
        """deprecated函数会返回一个叫inner的函数、inner函数会返回
        fun调用的结果,与直接调用fun得到值不同的是inner会先打印一行提示
        表明fun已经过时
        """
        def inner(x,y):
            print("{fun.__name__} 函数已经过时 请使用{new_fun_name}".format(fun=fun,new_fun_name=new_fun_name))
            return fun(x,y)
        return inner
    
    def add_fun(x,y):
        """
        实现两个数相加、并返回合
        """
        return x+y
    
    add_fun = deprecated(add_fun,'add')
    
    def add(x,y):
        """
        实现两个数相加、并返回合
        """
        return x+y    
    
    if __name__=="__main__":
        print(add_fun(1,1))

      调用时的输出如下:

    python3 dc.py
    add_fun 函数已经过时 请使用add
    2

    难道为装饰器增加参数就这么的简单

      仔细的你可能已经发现了、我们在上面的代码里并没有用装饰器的语法糖衣、而是通过函数调用的方式来包装的add_fun方法

    add_fun = deprecated(add_fun,'add')

      机智的你应该想到了@deprecated('add') 这样去装饰add_fun应该也能成吧!于是代码如下(关键代码)

    @deprecated('add')
    def add_fun(x,y):
        """
        实现两个数相加、并返回合
        """
        return x+y

      当你调用时会发现完全不是你想要的那样、

    python3 dc.py
    Traceback (most recent call last):
      File "dc.py", line 12, in <module>
        @deprecated('add')
    TypeError: deprecated() missing 1 required positional argument: 'new_fun_name'

      事实上目前语法糖衣只解决了最简单的情况、如果你要给@写法 指定参数还要另寻它法。

    真理简洁而有力

      linux的世界里有句话“一切皆文件”,python的世界里也有一句话“一切皆对象”; 但是关键不是会“背”,而是“领悟”。

      一个经典的糖衣格式是这样的

    @decorate
    def fun():
        pass

      请仔细看一下不难发现@后面直接是对象名、由python的数据模式可知、对象名只是一个对象的标识;也就是说@后面是一个对象!对象可以

      是已经定义好的,也可以是调用才生成。明白这一层道理之后事情就比较好办了,我们只要在调用时生成“装饰”对象就可以了,因为要调用

      所以就给了我们传递参数的机会。

    触摸真理一

       用调用时生成的对象用作装饰器

    def deprecated(new_fun_name):
        """derepcated 装饰器把函数标记为过时
        """
        def warpper(fun):
            """
            """
            def inner(*args):
                print("{0} 函数已经过时 请使用 {1}".format(fun.__name__,new_fun_name))
                return fun(*args)
            return inner
        
        return warpper
    
    decorator = deprecated('add') # 特意把这一步单独分离出来、用于说明什么叫调用时创建的对象用作做装饰器
    
    @decorator                    # 特意把这一步单独分离出来、用于说明什么叫调用时创建的对象用作做装饰器
    def add_fun(x,y):
        """
        实现两个数相加、并返回合
        """
        return x+y
    
    def add(x,y):
        """
        实现两个数相加、并返回合
        """
        return x+y    
    
    if __name__=="__main__":
       print(add_fun(1,1))

      

    触摸真理二

      与语法糖衣结合、完成传递参数的目的

    def deprecated(new_fun_name):
        """derepcated 装饰器把函数标记为过时
        """
        def warpper(fun):
            """
            """
            def inner(*args):
                print("{0} 函数已经过时 请使用 {1}".format(fun.__name__,new_fun_name))
                return fun(*args)
            return inner
        
        return warpper
    
    
    @deprecated('add')
    def add_fun(x,y):
        """
        实现两个数相加、并返回合
        """
        return x+y
    
    def add(x,y):
        """
        实现两个数相加、并返回合
        """
        return x+y    
    
    if __name__=="__main__":
       print(add_fun(1,1))

      调用时输出如下

    python3 dc.py
    add_fun 函数已经过时 请使用 add
    2

    总结:

      如果只能用一名话概括python我想对简洁的应该是“一切皆对象”了吧。

  • 相关阅读:
    去除字符串中的重复字符
    .net生成的类,跨工程调用显示注释
    Flex 页面空白或Error #2032: 流错误处理办法
    读取点阵字库
    SQL多表联合查询(Access数据库表)
    MSComm不能触发MSComm1_OnComm()事件原因之一
    一个小时内学习SQLite数据库(转)
    人生无悔
    学习之道
    挺经
  • 原文地址:https://www.cnblogs.com/JiangLe/p/9309566.html
Copyright © 2020-2023  润新知