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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:36:14