zoukankan      html  css  js  c++  java
  • 终于解决了使用Python装饰器的一个痛点

    如何给装饰器的参数传参,这个问题曾经困扰我好久,虽然Python版本的更新,现在这个问题终于解决了,特此记录。

    疑问

    首先我有一个这样的装饰器文件路径helper/log_helper.py

    import traceback
    from functools import wraps
    
    from loguru import logger
    
    
    def my_logger(count):
        def step1(foo):
            @wraps(foo)
            def step2(*args, **kwargs):
                try:
                    result = foo(*args, **kwargs)
                    logger.info(f"{result=},{count=}")
                except Exception:
                    logger.exception(traceback.format_exc())
    
            return step2
    
        return step1
    
    

    然后我有个文件需要引用这个装饰器demo.py

    from helper.log_helper import my_logger
    
    
    class Demo:
        @my_logger(count=2)
        def main(self):
            return "in main function"
    
    
    if __name__ == '__main__':
        d = Demo()
        d.main()
    

    输出结果如下

    2020-10-16 11:43:12.001 | INFO     | helper.log_helper:step2:18 - result='in main function',count=2
    

    这个装饰器的作用很简单,就是获取当前函数的返回值,和传入的count值。

    好,现在问题来了?

    如果给装饰器的参数传值呢,也就是说我的count=2,是通过传值的形式。你想到可能是这样

    from helper.log_helper import my_logger
    
    COUNT=2
    class Demo:
        @my_logger(count=COUNT)
        def main(self):
            return "in main function"
    
    
    if __name__ == '__main__':
        d = Demo()
        d.main()
    

    ok,这样确实可以,我们还可以使用再简化一步

    from functools import partial
    from helper.log_helper import my_logger
    
    COUNT=2
    my_logger = partial(my_logger,count=2)
    
    
    class Demo:
        @my_logger()
        def main(self):
            return "in main function"
    
    
    if __name__ == '__main__':
        d = Demo()
        d.main()
    

    暂时来看我们搞定了传参数的问题,这时候我们想如果外界调用了Demo类的main方法,并且向指定count的值怎么办呢?

    我们知道外界调用Demo类传参的唯一途径就是向__init__里进行传参数,按照这个思路我们只能这么写了,

    class Demo:
        def __init__(self):
            count =2
        @my_logger(count=self.count)
        def main(self):
            return "in main function"
    

    但是这样并不可以,我们得到错误信息

    NameError: name 'self' is not defined
    

    在装饰器中无法使用self.形式的参数,难道这个问题解决不了么?

    问题解决

    在Python3.7之前确实没什么可行的方案。

    我们知道在Python3.7的时候引入了dataclasses,我们可以通过它来简化__init__

    改下我们的代码

    from functools import partial
    
    from helper.log_helper import my_logger
    from dataclasses import dataclass
    
    @dataclass()
    class Demo:
        count: int = 2
        logger: my_logger = partial(my_logger, count)
    
        @logger()
        def main(self):
            return "in main function"
    
    
    if __name__ == '__main__':
        d = Demo()
        d.main()
    

    如果使用Python3.8那么可以直接忽略掉dataclass

    class Demo:
        count: int = 2
        logger: my_logger = partial(my_logger, count)
    
        @logger()
        def main(self):
            return "in main function"
    

    这样我们就成功的解决了这个问题,突然想起来之前遇到的这个难题,现在算是解决了,希望对你有帮助。

  • 相关阅读:
    C语言 sprintf 函数 C语言零基础入门教程
    C语言 printf 函数 C语言零基础入门教程
    C语言 文件读写 fgets 函数 C语言零基础入门教程
    C语言 文件读写 fputs 函数 C语言零基础入门教程
    C语言 fprintf 函数 C语言零基础入门教程
    C语言 文件读写 fgetc 函数 C语言零基础入门教程
    C语言 文件读写 fputc 函数 C语言零基础入门教程
    C语言 strlen 函数 C语言零基础入门教程
    Brad Abrams关于Naming Conventions的演讲中涉及到的生词集解
    适配器模式
  • 原文地址:https://www.cnblogs.com/c-x-a/p/13825402.html
Copyright © 2011-2022 走看看