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

__getattribute__与__getattr__问题排查及ATM代码修复咨询

问题分析与修复方案

为什么启用__getattribute__会触发NoneType错误?

当你重写Python类的__getattribute__方法时,它会拦截所有属性/方法的访问请求——不管这个属性是否存在。如果你的实现没有返回正确的属性对象(比如忘了写return,或者错误返回None),调用atm.add_rub(50)时,add_rub会被解析成None,自然就触发TypeError: 'NoneType' object is not callable。

举个你可能写错的反例:

class ATM:
    def __init__(self):
        self.rub_balance = 0

    def __getattribute__(self, name):
        # 只做了非法方法检查,但没返回合法方法对象
        if name.startswith('add_') and name != 'add_rub':
            raise ValueError("仅支持卢布")

    def add_rub(self, amount):
        self.rub_balance += amount

这个__getattribute__没有返回值,默认返回None,所以atm.add_rub拿到的是None,调用必报错。

正确写法是:合法的属性访问必须调用父类的__getattribute__获取原属性/方法并返回:

class ATM:
    def __init__(self):
        self.rub_balance = 0

    def __getattribute__(self, name):
        if name.startswith('add_') and name != 'add_rub':
            raise ValueError("本ATM仅支持卢布操作")
        # 合法请求交给父类处理,返回正确的方法对象
        return super().__getattribute__(name)

    def add_rub(self, amount):
        self.rub_balance += amount

更合理的实现:用__getattr__替代__getattribute__

你的需求(拦截非法货币方法)其实更适合__getattr__——它只在访问不存在的属性/方法时触发,不会干扰add_rub这类合法方法的正常调用,代码更简洁:

class ATM:
    def __init__(self):
        self._rub_balance = 0  # 改成私有属性,避免外部直接修改

    def __getattr__(self, name):
        if name.startswith('add_'):
            raise ValueError("本ATM仅支持卢布操作")
        # 其他不存在的属性按默认逻辑抛错
        raise AttributeError(f"'ATM' object has no attribute '{name}'")

    def add_rub(self, amount):
        # 增加输入验证:金额必须为正的数字
        if not isinstance(amount, (int, float)) or amount <= 0:
            raise ValueError("添加金额必须为正数")
        self._rub_balance += amount

    def get_rub_balance(self):
        return f"当前余额:{self._rub_balance} 卢布"

调用atm.add_usd(100)会触发__getattr__抛错,atm.add_rub(50)则直接执行正常逻辑,不会有任何问题。

其他可修复/优化点

  • 封装核心数据:把余额设为私有属性(比如_rub_balance),禁止外部直接修改,只能通过指定方法操作,保证数据安全。
  • 自定义异常类:可以定义UnsupportedCurrencyError替代通用的ValueError,让错误信息更精准。
  • 完善功能:添加withdraw_rub取款方法,同时做余额校验(取款金额不能超过当前余额)。
  • 统一异常处理:给所有操作添加规范的异常抛出逻辑,方便调用方捕获和处理错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 15:22:11