子类继承父类访问器属性后可用super()调用,但需注意:方法名必须严格一致;setter中应显式调用fset而非赋值;mro决定实际调用路径;且仅限实例方法中使用。

子类继承父类访问器属性(@property、@xxx.setter)后,用 super() 调用它们是完全可行的,但存在几个关键边界限制——不是语法报错,而是行为容易出错或不符合预期。核心问题不在于“能不能调”,而在于“调到谁”和“参数是否匹配”。
访问器方法名必须严格一致
Python 的 super() 是按 MRO 查找「同名方法」,而访问器本质是描述符对象,其底层绑定依赖方法名。如果子类重写了 @property,但 setter 名字变了(比如父类叫 _value,子类误写成 value_setter),super().value 或 super().value = x 就会失败。
- ✅ 正确:父类定义
@property和@xxx.setter,子类用相同名字重写,并在内部用super().xxx访问 - ❌ 错误:子类把 setter 命名为
set_value,再试图super().value = x—— 这会触发父类的 setter,但若父类没定义该属性或逻辑不兼容,就会抛AttributeError或静默失效
setter/getter 中 super() 必须显式传参(尤其在赋值时)
@property 的 getter 可以直接 return super().attr;但 setter 是普通方法,签名是 def attr(self, value):。当你写 super().attr = value,Python 实际调用的是 super().__setattr__('attr', value),这**不等于**调用父类的 @attr.setter。
- ✅ 安全做法:在 setter 内显式调用
super().attr.fset(self, value)(获取父类描述符的fset并手动执行) - ✅ 更常用:直接写
super().__class__.attr.fset(self, value),或退一步,在 setter 中用super().attr获取旧值,再做自定义逻辑 - ⚠️ 注意:
super().attr = value在多数情况下只是给实例动态加属性,绕过了父类 setter 的校验逻辑
多重继承下,MRO 决定“下一个”访问器归属
当多个父类都定义了同名 @property,super().attr 不一定走到你认为的“直接父类”,而是走到 MRO 序列中当前类之后的第一个有该属性的类。
- 例如:
class D(B, C): ...,且B和C都有@prop,那么D中的super().prop会先找B.prop(因为B在D.__mro__中排C前面) - 若
B的 getter 里又写了super().prop,它不会跳去A(即使A是B的父类),而是按B的 MRO 继续往后找——可能是C,也可能是A,取决于整个继承声明顺序 - 建议:用
D.__mro__或help(D)确认实际顺序,避免靠经验猜测
不能在 @staticmethod 或类方法外使用 super() 访问实例级访问器
super() 依赖绑定上下文(self 或 cls)。静态方法没有 self,无法构建代理对象;而访问器属性本身是绑定到实例的,脱离实例上下文就无意义。
- ❌
@staticmethod中写super().attr→RuntimeError: super(): no arguments - ❌ 类方法中尝试
super(cls, cls).attr→ 即使语法通过,也会因缺少实例而触发AttributeError(除非访问器是@classmethod风格,但这就不是标准 property 了) - ✅ 所有对访问器的
super()调用,必须发生在实例方法(含__init__、@xxx.setter等)中,且确保self已正确初始化











