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

Python自定义类作为类方法装饰器复用代码触发TypeError如何解决

问题根因
  1. 两种装饰用法的逻辑差异:
  • 无参数@Decorator:类的方法属性直接是Decorator实例,该实例实现了__get__描述符协议,访问时会自动绑定类实例作为第一个参数,所以运行正常。
  • 带参数@Decorator():先实例化Decorator对象,再调用该对象的__call__方法传入被装饰函数,返回值会作为类的方法属性。
  1. 报错的核心原因:
    修改后__call__直接返回self.call,这是已经绑定到Decorator实例的绑定方法。Python的方法绑定规则是:只有未绑定的普通函数作为类属性存在时,通过实例访问才会自动把实例作为第一个参数传入;已经绑定的方法不会触发该逻辑,所以调用hello_world.print("Max Musterman")时,实例没有被传入call方法,call拿到的第一个参数是字符串"Max Musterman",传给原方法时缺少name参数,触发报错。
    你观察到的inspect.signature返回一致,是因为inspect会自动隐藏绑定方法的self参数,本质上两个可调用对象的类型完全不同,作为类方法属性的行为也完全不同。
解决方案

不需要直接返回self.call,只要在wrapper中调用self.call即可复用逻辑,不存在重复代码问题,还可以用functools.wraps保持原函数的元信息:

from functools import partial, wraps

class Decorator:
    def __init__(self, func = None, *args):
        self.uses_init = func is None
        self.func = func
        self.instance = None
        self.args = args
    
    def __call__(self, *args, **kwargs):
        self.func = args[0]
        @wraps(self.func)
        def wrapper(cls, *args, **kwargs):
            return self.call(cls, *args, **kwargs)
        return wrapper
    
    def call(self, cls, *args, **kwargs):
        print('before')
        parsed_func = self.func(cls, *args, **kwargs)
        print('after')
        return parsed_func       

    def __get__(self, instance, owner):
        # This is only used when uses_init == False
        return partial(self.call, instance)

该实现完全兼容你原来的测试用例,所有核心逻辑都统一在call方法中维护。

内容的提问来源于stack exchange,提问作者PythonF

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 03:45:01