使用装饰器猴子补丁class.__str__方法失效问题排查
问题根源分析
你的装饰器结构出现了错误,导致MyClass最终被替换成了内部的decorator函数,而不是你期望的修改了__str__方法的类。具体过程是这样的:
- 当你使用
@str_patcher装饰MyClass时,Python会执行MyClass = str_patcher(MyClass)。 str_patcher接收原MyClass作为klass参数,然后返回内部定义的decorator函数。这意味着现在MyClass这个名称指向的是decorator函数,而不是原来的类。- 当你调用
MyClass(a=1, b=2, c=3)时,本质是调用decorator(a=1, b=2, c=3)。这个函数内部确实修改了原klass(最初的MyClass)的__str__方法,但最后返回的是klass本身——也就是原类对象,而不是类的实例。 - 所以
print(...)打印的是类对象,而不是实例,自然输出<class __main__.MyClass>。
修复方案
有两种简单的修复方式,取决于你是否需要装饰器支持额外参数:
方案1:简化装饰器(无额外参数场景)
直接去掉不必要的嵌套,让装饰器直接接收类作为参数,修改后返回类:
def str_patcher(klass): def __str__(self): items = {key: value for key, value in self.__dict__.items() if not key.startswith("_")} return f"{type(self).__qualname__}({items})" klass.__str__ = __str__ return klass @str_patcher class MyClass: def __init__(self, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) # 测试 print(MyClass(a=1, b=2, c=3)) # 输出:MyClass({'a': 1, 'b': 2, 'c': 3})
方案2:保留嵌套结构(支持未来扩展参数)
如果以后需要给装饰器加参数(比如自定义过滤规则),可以调整成“装饰器工厂”的结构,使用时需要调用str_patcher():
def str_patcher(): def decorator(klass): def __str__(self): items = {key: value for key, value in self.__dict__.items() if not key.startswith("_")} return f"{type(self).__qualname__}({items})" klass.__str__ = __str__ return klass return decorator @str_patcher() # 注意这里要加括号 class MyClass: def __init__(self, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) # 测试 print(MyClass(a=1, b=2, c=3)) # 输出:MyClass({'a': 1, 'b': 2, 'c': 3})
内容的提问来源于stack exchange,提问作者Alan Bagel
相关产品推荐
相关产品推荐

