如何实现带参和无参场景均可正常使用的类形式Decorator?
类装饰器兼容带/不带括号调用的实现方案
问题根因
- 带括号调用
@DecByClass():会先执行类构造方法生成装饰器实例,再将被装饰函数传入实例的__call__方法,返回包装函数,符合你的现有逻辑 - 不带括号调用
@DecByClass:会直接将被装饰函数作为第一个参数传入类的__init__构造方法生成实例,不会触发你写的__call__装饰逻辑,调用原函数时才会触发实例的__call__方法,此时传入的第一个参数是函数调用的入参,逻辑完全错位,因此无法生效
兼容实现方案
需要在__call__方法中对入参类型做判断,区分两种调用场景:
class DecByClass: def __init__(self, retry=None, *args, **kwargs): self._retry = retry self._func = None # 处理不带括号场景:__init__直接接收被装饰函数 if callable(retry): self._func = retry self._retry = 3 # 可自定义默认重试次数 def __call__(self, *args, **kwargs): # 不带括号场景:__call__接收函数调用入参,直接执行包装逻辑 if self._func is not None: # 此处写入装饰器核心逻辑,示例为重试 for _ in range(self._retry): try: return self._func(*args, **kwargs) except Exception: continue raise RuntimeError("重试次数耗尽") # 带括号场景:__call__第一个参数是被装饰函数,返回包装函数 func = args[0] def wrapper(*f_args, **f_kwargs): for _ in range(self._retry if self._retry is not None else 3): try: return func(*f_args, **f_kwargs) except Exception: continue raise RuntimeError("重试次数耗尽") return wrapper
测试验证
两种写法都可以正常运行:
# 带括号传参写法 @DecByClass(retry=5) def try_with_brackets(t): return str(t) # 不带括号写法 @DecByClass def try_without_brackets(t): return str(t) print(try_with_brackets(2)) # 输出 2 print(try_without_brackets(2)) # 输出 2
内容的提问来源于stack exchange,提问作者dmitriy_one
相关产品推荐
相关产品推荐

