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

为何在__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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:56:03