终于解决了使用Python装饰器中的一个痛点

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

 前言

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

[[346777]]

疑问

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

 

  1. import traceback 
  2. from functools import wraps 
  3.  
  4. from loguru import logger 
  5.  
  6.  
  7. def my_logger(count): 
  8.     def step1(foo): 
  9.         @wraps(foo) 
  10.         def step2(*args, **kwargs): 
  11.             try: 
  12.                 result = foo(*args, **kwargs) 
  13.                 logger.info(f"{result=},{count=}"
  14.             except Exception: 
  15.                 logger.exception(traceback.format_exc()) 
  16.  
  17.         return step2 
  18.  
  19.     return step1 

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

 

  1. from helper.log_helper import my_logger 
  2.  
  3.  
  4. class Demo: 
  5.     @my_logger(count=2) 
  6.     def main(self): 
  7.         return "in main function" 
  8.  
  9.  
  10. if __name__ == '__main__'
  11.     d = Demo() 
  12.     d.main() 

输出结果如下

 

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

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

好,现在问题来了?

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

 

  1. from helper.log_helper import my_logger 
  2.  
  3. COUNT=2 
  4. class Demo: 
  5.     @my_logger(count=COUNT
  6.     def main(self): 
  7.         return "in main function" 
  8.  
  9.  
  10. if __name__ == '__main__'
  11.     d = Demo() 
  12.     d.main() 

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

 

  1. from functools import partial 
  2. from helper.log_helper import my_logger 
  3.  
  4. COUNT=2 
  5. my_logger = partial(my_logger,count=2) 
  6.  
  7.  
  8. class Demo: 
  9.     @my_logger() 
  10.     def main(self): 
  11.         return "in main function" 
  12.  
  13.  
  14. if __name__ == '__main__'
  15.     d = Demo() 
  16.     d.main() 

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

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

 

  1. class Demo: 
  2.     def __init__(self): 
  3.         count =2 
  4.     @my_logger(count=self.count
  5.     def main(self): 
  6.         return "in main function" 

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

 

  1. NameError: name 'self' is not defined 

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

问题解决

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

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

改下我们的代码

 

  1. from functools import partial 
  2.  
  3. from helper.log_helper import my_logger 
  4. from dataclasses import dataclass 
  5.  
  6. @dataclass() 
  7. class Demo: 
  8.     countint = 2 
  9.     logger: my_logger = partial(my_logger, count
  10.  
  11.     @logger() 
  12.     def main(self): 
  13.         return "in main function" 
  14.  
  15.  
  16. if __name__ == '__main__'
  17.     d = Demo() 
  18.     d.main() 

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

 

  1. class Demo: 
  2.     countint = 2 
  3.     logger: my_logger = partial(my_logger, count
  4.  
  5.     @logger() 
  6.     def main(self): 
  7.         return "in main function" 

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

责任编辑:华轩 来源: Python学习开发
相关推荐

2020-04-13 16:05:25

JS装饰器前端

2011-04-01 09:49:54

Python

2010-02-01 17:50:32

Python装饰器

2022-02-01 15:40:30

iOS漏洞安全

2016-09-23 20:46:53

2019-12-02 11:27:35

携号转网号码

2014-04-08 09:49:27

PostgreSQL双缓冲

2022-09-07 10:20:05

Python装饰类

2022-01-05 08:58:08

Python解释器编程语言

2021-04-11 08:21:20

Python@property装饰器

2021-04-20 11:03:26

人工智能AI机器学习

2019-11-28 08:42:31

携号转网网络5G

2021-08-09 10:24:21

技术分类数学

2020-09-11 09:10:28

区块链版权文化产业数字化

2022-07-01 16:08:32

区块链区块链技术

2024-01-23 08:42:27

炎凰数据可视化监测容器云原生

2016-11-01 09:24:38

Python装饰器

2012-07-13 10:01:03

2021-09-27 10:03:55

装饰器代码

2017-01-12 09:40:47

点赞
收藏

51CTO技术栈公众号