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"
    

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

  • 相关阅读:
    JVM 的主要组成部分及其作用
    一天一个 Linux 命令(5):pwd命令
    算法-经典趣题-马踏棋盘(又称骑士周游)
    SAP HANA Schemas 和 HDI Containers
    如何手动下载并安装 Visual Studio Code 的 SAP Fiori tools
    一个最简单的 Github workflow 例子
    SAP UI5 初学者教程之七
    最近看的动漫和电影
    关于工作,干了这碗鸡汤
    啊啊啊啊啊啊
  • 原文地址:https://www.cnblogs.com/c-x-a/p/13825402.html
Copyright © 2011-2022 走看看