为何对象描述符的内部属性名需与原名称不同?递归错误解惑
为什么描述符内部名称要和原属性名不同?
递归错误的根源
当你在类中定义描述符属性(比如class MyClass: foo = x()),Python会将类层面的foo识别为描述符。当访问实例的foo属性(如obj.foo)时,Python会自动触发描述符的__get__方法。
在你最初的代码里,__set_name__将internal_name设为和属性名完全相同的字符串(比如属性名是foo,internal_name就是foo)。这导致__get__方法中执行getattr(instance, self.internal_name)时,相当于再次访问obj.foo——而这个操作又会触发描述符的__get__方法,形成无限递归,直到超过Python的递归深度限制,抛出RecursionError。
修改后解决问题的原理
将internal_name改为f'_{name}'(比如属性名是foo,internal_name变成_foo)后,getattr(instance, '_foo')访问的是实例自身存储的普通属性,而非绑定了描述符的公开属性。这个带下划线的属性并没有关联描述符逻辑,所以直接返回存储的值,不会再次触发__get__,递归也就终止了。
本质上,这是描述符的常规设计思路:用公开属性名(如foo)挂载描述符逻辑,用带前缀的内部名称(如_foo)存储实际值,避免属性名冲突导致的递归调用。
内容的提问来源于stack exchange,提问作者Tim Sananikone
相关产品推荐
相关产品推荐

