Python OOP中使用@property装饰器触发递归错误的疑问
为什么使用@property装饰器时直接赋值self.name会触发递归错误?
这绝对是刚上手@property时最容易踩的坑之一,我来给你讲明白背后的逻辑:
首先得搞懂@property到底在干啥——当你用它装饰一个方法时,Python会把这个方法包装成一个属性访问器。也就是说,当你写james.name的时候,你不是在直接访问实例的name属性,而是在调用被@property装饰的name()方法;同理,当你写james.name = 'xxx'时,你也不是直接给属性赋值,而是在调用被@name.setter装饰的setter方法。
那回到你的代码里,问题就出在这两行:
- getter里的
return self.name:当你试图返回self.name时,Python会触发getter方法本身的调用,相当于无限递归调用name()方法; - setter里的
self.name = newname:当你试图给self.name赋值时,Python会触发setter方法本身的调用,相当于无限递归调用setter方法。
这样来回调用下去,很快就会超过Python的递归深度限制,自然就抛出RecursionError了。
那为什么改成self._name就没问题呢?因为self._name是直接操作实例的一个私有实例变量(Python里用下划线开头约定为内部使用的变量),这不会触发@property定义的getter和setter逻辑,只是单纯地读写实例上的原始数据,完美打破了递归循环。
给你贴个修正后的完整代码,一看就懂:
class Person(object): @property def name(self): return self._name # 直接返回内部存储的私有变量 @name.setter def name(self, newname): self._name = newname # 直接给内部私有变量赋值 james = Person() james.name = 'James Bond' print(james.name) # 正常输出: James Bond
总结一下核心要点:
@property的本质是把方法伪装成属性访问,所以在getter和setter内部,绝对不能直接访问被装饰的那个属性名(比如这里的name),否则必然触发递归;- 一定要用一个单独的实例变量(通常带下划线前缀)来存储实际数据,把属性访问器和底层存储变量区分开。
内容的提问来源于stack exchange,提问作者jxie0755
相关产品推荐
相关产品推荐

