Python抽象类继承@property setter装饰器实例化报错问题咨询
报错根本原因
你使用@C.x.setter装饰子类setter方法时,意外覆盖了子类自定义的getter实现,最终子类的x属性仍然保留了父类的抽象标记,被abc模块判定为抽象方法,所以无法实例化。
背后实现逻辑
1. 抽象property的标记规则
abc模块判定一个property是否为抽象的规则是:只要property的fget/fset/fdel任意一个组件带有__isabstractmethod__=True的标记,且没有被替换为具体实现,整个property就会被判定为抽象。
你在父类C中同时给x的getter、setter都加了@abstractmethod装饰,所以父类C.x的fget和fset两个组件都被标记为抽象。
2. 两种setter装饰写法的差异
可运行写法:@x.setter
你在子类D中的代码执行顺序是:
- 先用
@property装饰自定义的getter方法,此时子类命名空间里生成了一个全新的xproperty对象,它的fget是你写的具体实现,没有抽象标记。 - 再用
@x.setter装饰自定义的setter方法,这里的x就是上一步生成的子类property对象,装饰后只是给这个对象绑定了具体的fset,整个property全是具体实现,abc判定为非抽象,所以可以正常实例化。
报错写法:@C.x.setter
@C.x.setter是父类property对象提供的装饰器,它的作用是基于父类的property生成新的property,默认复用父类的fget,仅替换fset。
你的代码执行顺序变成:
- 先用
@property生成了子类的xproperty,包含你写的具体getter。 - 再用
@C.x.setter装饰setter,生成了一个新的property对象:它的fget是父类C.x的抽象getter,fset是你写的具体setter,这个新对象直接覆盖了上一步的子类xproperty。
此时子类D.x的fget仍然是父类的抽象实现,自然会被abc判定为抽象方法,触发实例化报错。
3. 和官方文档示例的差异
官方文档中使用@C.x.setter的示例,前提是父类property只有部分组件是抽象的:比如仅setter是抽象的,getter是具体实现。这种场景下子类不需要重写getter,直接用@C.x.setter替换抽象setter后,整个property就全是具体实现,不会触发报错。你的场景是父类x的getter、setter全是抽象的,自然不能直接复用父类的fget。
内容的提问来源于stack exchange,提问作者Yehui He
相关产品推荐
相关产品推荐

