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

带参数的类作为装饰器时,如何获取类实例而非__call__返回的函数?

带参数的类作为装饰器时,如何获取类实例而非__call__返回的函数?

嘿,我太懂你遇到的这个坑了——之前写的类装饰器最后把被装饰的函数变成了包装后的普通函数,导致想调用metadata()这类自定义方法根本找不到入口,对吧?核心问题就是没摸准带参数的类装饰器的执行逻辑,咱们一步步把它掰正。

首先得把带参数类装饰器的执行流程理清楚:

  • 当你写@step(tags=[...], ...)时,Python会先调用step的__init__,把装饰器参数传进去,先创建一个step类的实例;
  • 紧接着,这个实例会被自动调用,参数就是你要装饰的那个函数(比如test);
  • 最后,这次调用的返回值会被赋值给test变量。

你之前的写法里,__call__返回的是包装后的函数,所以test就变成了普通函数,自然没法调用类的实例方法。咱们要做的,就是让__call__返回类实例本身,这样test就是step的实例,既能当函数调用,又能调用metadata()这类自定义方法。

下面是修正后的完整代码,完全贴合你的需求:

class step:
    def __init__(self, version, description, tags):
        # 第一步:先接收装饰器的参数,此时还没拿到要装饰的函数
        self._version = version
        self._description = description
        self._tags = tags
        self._wrapped_func = None  # 存被orchestrator装饰后的函数
        self._original_func = None  # 可选:保留原函数,方便后续扩展

    def __call__(self, func):
        # 第二步:接收被装饰的函数,完成装饰逻辑
        self._original_func = func
        # 把orchestrator装饰器应用到原函数上,保留它的原有功能
        self._wrapped_func = orchestrator(
            tags=self._tags,
            version=self._version
        )(func)
        # 关键操作!返回实例本身,这样被装饰后的变量就是step的实例
        return self

    def __call__(self, *args, **kwargs):
        # 第三步:当用户像调用普通函数一样用test(1,2)时,执行这段逻辑
        if not self._wrapped_func:
            raise ValueError("还没有装饰任何函数哦!")
        # 直接调用被orchestrator装饰后的函数,完全保留原装饰器的能力
        return self._wrapped_func(*args, **kwargs)

    def metadata(self):
        # 你想要的元数据方法,直接返回整理好的字典
        return {
            "version": self._version,
            "description": self._description,
            "tags": self._tags,
        }

    # 后续想加新方法直接在这里加就行,比如给标签新增内容的方法
    def add_tags(self, new_tags):
        if isinstance(new_tags, list):
            self._tags.extend(new_tags)
        else:
            self._tags.append(new_tags)
        # 如果需要同步更新orchestrator里的元数据,这里可以补充对应逻辑

用这个装饰器的方式和你最初想的完全一样:

@step(
    tags = ["test"],
    description = "这是一个示例加法函数",
    version = "0.1"
)
def test(a,b):
    return a+b

现在你再试试这些操作:

  • 调用test(2,3):会执行被orchestrator装饰后的函数,返回5,完全保留原装饰器的所有功能;
  • 调用test.metadata():会直接返回你定义的元数据字典{"version": "0.1", "description": "这是一个示例加法函数", "tags": ["test"]};
  • 调用test.add_tags(["new_tag1", "new_tag2"]):可以给实例添加新标签,再调用metadata()就能看到更新后的内容。

这个写法的优势太明显了:

  1. 完全符合Python带参数装饰器的执行逻辑,流程清晰不绕弯;
  2. 被装饰后的变量是类实例,兼顾了“像普通函数一样调用”和“能调用自定义方法”两个核心需求;
  3. 扩展性拉满,后续要加新功能直接在step类里加方法就行,不用大改原有结构。

之前踩坑主要是没搞懂带参数类装饰器的两步流程,还错误地让__call__返回了包装函数而非实例本身,现在这个写法就完美规避了这些问题,绝对是Pythonic的标准实现方式!

备注:内容来源于stack exchange,提问作者BBG

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:50:29