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

为何无法在__setattr__中以{attr:value}形式为属性赋值?

为什么在__setattr__里用self.__dict__ = {attr:value}会触发递归错误?

问题重现

我们可以直接通过给对象的__dict__赋值来设置属性:

class Room():
    pass

# 创建实例
r = Room()
# 直接通过__dict__设置name属性
r.__dict__ = {'name':'r1'}
print(r.name)  # 输出 'r1'

但当我们重写Room类的__setattr__方法后,创建实例会直接触发递归错误:

class Room:
    def __init__(self,name):
        self.name = name
    def __setattr__(self,attr,value):
        self.__dict__ = {attr:value}

# 创建实例时触发报错
r = Room('r1')

报错信息:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
  File "<stdin>", line 5, in __setattr__
  File "<stdin>", line 5, in __setattr__
  File "<stdin>", line 5, in __setattr__
  [Previous line repeated 994 more times]
RecursionError: maximum recursion depth exceeded

我们可以用self.__dict__[attr] = value修复这个问题,但得搞清楚为什么前者不行。

核心原因

在Python里,所有对对象属性的赋值操作(包括给__dict__本身赋值)都会自动触发__setattr__方法。

当你在自定义的__setattr__里写self.__dict__ = {attr:value}时,这本质是在给self的__dict__属性赋值,Python会立刻调用你重写的__setattr__方法;而新进入的__setattr__又会执行self.__dict__ = ...,再次触发自身调用——这样就形成了无限递归,直到达到Python的递归深度上限,抛出报错。

而用self.__dict__[attr] = value时,你是直接修改__dict__这个字典对象的内部条目,不是给__dict__属性本身赋值,所以不会触发__setattr__,自然不会有递归问题。

另外还有一种安全的写法:调用父类的__setattr__方法,比如super().__setattr__(attr, value),这样也能绕过自定义的__setattr__逻辑,避免递归。

内容的提问来源于stack exchange,提问作者showkey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:22:47