You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现带参和无参场景均可正常使用的类形式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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 13:48:03