Python中使用__setattr__时出现AttributeError与RecursionError求助
问题分析与修复方案
第一个版本代码的错误原因
第一个版本中,__init__里执行self._treasure = "gold"时,会自动调用自定义的__setattr__方法。此时self._attributes还未被初始化,__setattr__里访问self._attributes[name] = value就会触发“不存在'_attributes'属性”的警告。
另外,super().__setattr__("_attributes", dict(self.__dict__))逻辑冗余:你已经在修改self._attributes,又通过父类方法重新设置一次,完全没必要,而且此时self.__dict__里还没包含最新的value,反而会导致数据不一致。
第二个版本代码的递归错误原因
修改后的代码里,__setattr__最后执行self._attributes = dict(self.__dict__),这行赋值操作会再次触发__setattr__(因为给实例属性赋值都会调用该方法),形成无限递归,最终导致RecursionError。
修复方案
要实现“treasure属性正常返回'gold',检测到属性新增或修改时输出提示”的目标,需要避免初始化和属性设置时的递归,同时正确维护属性快照。修复后的代码如下:
class Vault: def __init__(self): # 直接操作__dict__初始化属性,绕过自定义__setattr__,避免递归 self.__dict__['_treasure'] = "gold" self.__dict__['_attributes'] = dict(self.__dict__) def __setattr__(self, name, value): # 检测属性是否为新增,或已有属性值被修改 if name not in self._attributes or self._attributes[name] != value: print("attribute deleted!") # 更新属性快照 self._attributes[name] = value # 调用父类的__setattr__完成实际赋值,避免触发自定义方法的递归 super().__setattr__(name, value) @property def treasure(self): # 检查当前属性状态与快照是否一致 if self.__dict__ != self._attributes: print("attribute deleted!") return self._treasure
关键修复点说明
- 初始化阶段:直接操作
self.__dict__来设置初始属性,避免触发自定义的__setattr__,确保_attributes能被正常创建并保存初始状态。 - __setattr__逻辑:
- 先判断属性是新增还是值被修改,满足条件时输出提示。
- 更新
_attributes快照后,调用super().__setattr__完成实际属性赋值,这里调用的是父类(object)的原生方法,不会再次触发自定义的__setattr__,避免递归。
- treasure属性检查:保留原有的快照对比逻辑,读取属性时如果状态不一致,输出提示。
测试示例
v = Vault() print(v.treasure) # 输出: gold(初始状态一致,无提示) v.new_attr = 123 # 输出: attribute deleted!(新增属性) v._treasure = "silver" # 输出: attribute deleted!(修改属性值) print(v.treasure) # 输出: attribute deleted! 然后输出: silver(状态不一致触发提示)
内容的提问来源于stack exchange,提问作者Karenzz
相关产品推荐
相关产品推荐

