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

Python类装饰器@typed失效求助:Holding类类型校验异常

问题分析与解决方案

你的问题核心在于自定义的__setattr__方法绕过了Python描述符的默认执行流程,导致@typed装饰器配置的类型校验逻辑没有被触发。

为什么会这样?

Python中,当你给实例属性赋值时,默认的__setattr__逻辑是这样的:

  • 先检查该属性对应的类属性是否是一个实现了__set__方法的描述符(比如你的Typed子类)
  • 如果是描述符,会优先调用描述符的__set__方法,而不是直接修改实例的__dict__

但你的Holding类重写了__setattr__,直接调用super().__setattr__(name, value)(也就是object类的__setattr__),这会直接把值存入实例的__dict__,完全跳过了描述符的检查和调用流程。所以即使@typed装饰器已经给描述符设置了name属性,它们的__set__方法根本没机会执行,类型校验自然不生效。

另外,你看到的属性值混乱(比如输出里的3.45 2018-01-09 3.45 3.45 11.9025...),是因为在装饰器未正确生效时,描述符的__get__方法里self.name是None,但实例__dict__里没有None这个键——其实是因为当实例__dict__里存在同名属性时,Python会直接返回实例属性,而不会调用描述符的__get__。你之前的赋值操作已经把name、shares等直接存入了实例__dict__,所以描述符的__get__根本没被调用,直到你在main()里手动给描述符设置了name,后续的属性访问才触发了__get__,但此时实例__dict__里的键和描述符的name不匹配,导致取错了值。

如何修复?

修改Holding类的__setattr__方法,在赋值前先检查类中是否存在对应的描述符,如果存在则调用描述符的__set__,否则再执行原有的逻辑:

def __setattr__(self, name, value):
    if name not in {'name', 'date', 'shares', 'price'}:
        raise AttributeError(f'No attribute {name}')
    # 先检查类属性是否是描述符
    cls_attr = getattr(type(self), name, None)
    if isinstance(cls_attr, Typed):
        cls_attr.__set__(self, value)
    else:
        super().__setattr__(name, value)

同时,你会看到装饰器里的print('in typed():', obj.name)正常输出name、shares、price,说明描述符的name属性已经被正确设置。

验证修复效果

修改后运行代码,你会得到符合预期的输出:

in typed(): name
in typed(): shares
in typed(): price
ABC 2018-01-09 500 3.45 1725.0
No attribute time
Expected <class 'int'>
ABC 2018-01-09 100 3.45 345.0
in main():  name
in main():  shares
in main():  price

类型校验逻辑正常触发,属性值也不会再混乱了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:51:03