为何无法在__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
相关产品推荐
相关产品推荐

