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

使用@property+setter封装账户编号时触发无限递归的原因?

解析@property实现中触发无限递归的原因

你遇到的无限递归问题,根源在于@property的实现逻辑错误,没有区分属性的实际存储变量和访问器方法:

问题代码

class SingleBankAccount:
    
    def __init__(self, account_number, account_balance):
        self.account_number = account_number
        self.account_balance = account_balance
        
    @property
    def account_number(self):
        return self.account_number
        
    @account_number.setter
    def account_number(self, number):
        # if there is a number already, raise exception, otherwise set it
        if self.account_number:
            raise AccountException("Someone tried to change the account number!")
        else:
            self.account_number = number

报错信息

File "main.py", line 17, in account_number

    if self.account_number:

  File "main.py", line 13, in account_number

    return self.account_number

  File "main.py", line 13, in account_number

    return self.account_number

  File "main.py", line 13, in account_number

    return self.account_number

  [Previous line repeated 993 more times]

RecursionError: maximum recursion depth exceeded

递归原因详解

  • Getter方法的无限递归
    当你用@property装饰account_number方法后,self.account_number不再是直接访问实例属性,而是会调用这个getter方法。而你的getter里写了return self.account_number,这会再次调用getter方法,形成无限循环,直到触发Python的递归深度限制。

  • Setter方法的双重递归
    在setter方法中存在两处递归触发点:

    • 判断if self.account_number:时,会调用getter方法,再次进入递归循环
    • 执行self.account_number = number时,会调用setter方法本身,同样形成递归

本质问题是:你没有用一个独立的变量来存储account_number的实际值,而是直接在getter/setter里操作同名的"属性",而这个"属性"其实是被@property包装后的方法,导致每次访问或赋值都在调用方法自身。

修复方案

使用下划线开头的私有变量(比如_account_number)存储实际值,getter和setter操作这个私有变量,避免递归:

class AccountException(Exception):
    pass

class SingleBankAccount:
    
    def __init__(self, account_number, account_balance):
        self._account_number = account_number
        self.account_balance = account_balance
        
    @property
    def account_number(self):
        return self._account_number
        
    @account_number.setter
    def account_number(self, number):
        if self._account_number:
            raise AccountException("Someone tried to change the account number!")
        else:
            self._account_number = number

这样外部通过account_number属性访问时,会自动调用getter/setter,而内部存储用_account_number,不会触发递归,同时实现了禁止修改账号的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 07:20:53