为何在__init__中用super().__setattr__而非直接赋值避免递归?
为什么__init__直接赋值会触发无限递归,而super().__setattr__不会?
问题回顾
你最初实现的ButtonWrapper包装类代码如下:
class ButtonWrapper: def __init__(self, button: Button, attributes: ExtraButtonAttributes): self.button = button self.extraAttributes = attributes def __getattr__(self, key): return getattr(self.button, key) def __setattr__(self, key, value): if hasattr(self.button, key): setattr(self.button, key, value) else: setattr(self.extraAttributes, key, value)
这段代码在调用getattr时出现无限递归,经修复后__init__改为:
def __init__(self, button: Button, attributes: ExtraButtonAttributes): super().__setattr__('button', button) super().__setattr__('extraAttributes', attributes)
修复后代码正常运行,但你疑惑两种赋值方式的区别及为何后者不会触发递归。
原代码递归的核心原因
当你执行self.button = button这类直接赋值操作时,Python会自动调用当前类(ButtonWrapper)重写的__setattr__方法。而你的__setattr__方法第一行就执行hasattr(self.button, key)——此时self.button还未完成初始化,常规属性查找找不到这个属性,就会触发你重写的__getattr__方法。__getattr__里又调用getattr(self.button, key),这又要去查找self.button,再次触发__getattr__,最终形成无限递归。
直接赋值与super().__setattr__的核心区别
- 直接赋值
self.attr = value:会优先调用当前类自定义的__setattr__(如果已重写)。这里你重写的__setattr__依赖未初始化的self.button,自然会引发逻辑冲突。 super().__setattr__('attr', value):直接调用父类(默认是object类)的原生__setattr__方法,完全绕过你自定义的__setattr__逻辑。原生__setattr__会直接将属性存入实例的__dict__字典中,不会触发任何自定义的属性访问逻辑,因此能安全完成button和extraAttributes的初始化。
额外说明
__getattr__方法只有在常规属性查找(即从实例__dict__、类属性等)失败时才会被触发。当用super().__setattr__完成初始化后,后续访问self.button会直接从实例__dict__中获取,不会再触发__getattr__,后续的__setattr__逻辑也能正常执行。
内容的提问来源于stack exchange,提问作者Simon Klaver
相关产品推荐
相关产品推荐

