Python重写属性时执行流程中断问题求助
问题场景
定义Chicken类:
class Chicken: def __init__(self): self._colour = "yellow" @property def colour(self): return self._colour
委托类ChickenDelegator:
class ChickenDelegator: def __init__(self, delegatee): self._delegatee = delegatee self._props = [ "colour" ] def get_delegatee(self): return self.__dict__["_delegatee"] def __getattr__(self, name): if name in self.__dict__["_props"]: return getattr(self.get_delegatee(), name) return super().__getattr__(name) def __setattr__(self, name, value): if "_props" in self.__dict__ and name in self.__dict__["_props"]: setattr(self.get_delegatee(), name, value) super().__setattr__(name, value)
子类Vulture:
class Vulture(ChickenDelegator): def __init__(self): super().__init__(Chicken()) @property def colour(self): print("Vulture colour property called") res = super().colour # 执行流程在此处中断!? #res = self.get_delegatee().colour # 此方式可行 print("使用super().colour时不会执行到这一行!") res = f"brown and {res}" return res
测试场景:
if __name__ == "__main__": v = Vulture() print(f"Vulture is {v.colour}") # 预期输出: "Vulture is brown and yellow" # 实际输出: "Vulture is yellow"
在Vulture类的colour属性中,使用super().colour能返回正确值,但执行流程会在此处中断;而使用self.get_delegatee().colour时,不仅能返回正确值,执行流程还能继续,这是期望的行为。请问为何在此场景下使用super().property_name会导致执行流程中断?
相关评论翻译
在他的案例中,流程中断是因为手动抛出了异常。如果我把
raise AttributeError(...)语句替换成return 100,执行流程会按预期从F返回到G再回到主程序。另外,在我的案例中__getattribute__的表现完全相同,而在他的案例中这解决了问题。
问题原因解析
你遇到的核心问题源于super()属性查找与__getattr__的交互逻辑,结合代码实际运行情况,流程中断的真实原因及逻辑如下:
super()的属性查找逻辑
当在Vulture的colourgetter中调用super().colour时,super()代理的是父类ChickenDelegator,但ChickenDelegator本身没有定义colour类属性(如property),因此Python会触发当前实例(Vulture对象v)的__getattr__方法(继承自ChickenDelegator)。__getattr__的直接返回特性ChickenDelegator.__getattr__会直接返回委托对象Chicken实例的colour属性值(字符串"yellow"),而非一个可进一步处理的property对象。但理论上这并不会导致流程中断——Vulture的colourgetter应该继续执行后续代码,将结果拼接为"brown and yellow"。流程中断的真实诱因
你观察到的"流程中断"大概率是因为Vulture的colourproperty根本没有被触发,常见原因包括:Vulture的colourproperty存在缩进错误(比如被嵌套在__init__方法内部,成为局部函数而非类属性);- 代码运行环境的缓存或其他干扰,导致
Vulture的类属性未被正确识别。
解决方案
- 检查
Vulture类中@property装饰的colour方法的缩进,确保它是类的直接成员,而非__init__的内部函数; - 优先使用
self.get_delegatee().colour的方式,直接访问委托对象的属性,避免super()和__getattr__的复杂交互; - 若坚持使用
super(),可在ChickenDelegator中显式定义colourproperty,替代__getattr__的委托逻辑:
这样class ChickenDelegator: # ... 其他代码 ... @property def colour(self): return self.get_delegatee().coloursuper().colour会直接调用ChickenDelegator的colourproperty,返回委托对象的属性值,同时Vulture的colourgetter后续代码会正常执行。
内容的提问来源于stack exchange,提问作者unsinkable2

