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

Python使用__getattr__重载运算符时+号失效及内核崩溃问题咨询

问题解答

1. 运算符语法不生效的问题

原因

Python 对__xx__格式的魔术方法的查找逻辑和普通属性完全不同:运算符触发的魔术方法查找会直接跳过实例的属性访问流程(不会触发实例的__getattr__方法),仅在类的命名空间中查找对应方法。
你的代码中Foo类本身没有定义__add__方法,所以bar + 1语法找不到对应实现触发报错;而直接调用bar.__add__(1)属于普通属性访问,会正常触发实例的__getattr__逻辑返回对应的add方法,所以可以正常执行。

解决方法

方案1:批量挂载预定义运算符

如果你已经明确需要重载的运算符列表,可以在类定义完成后批量给类挂载魔术方法:

class Foo():
    def add(self, other):
        return 1 + other
    def sub(self, other):
        return 1 - other

# 批量绑定魔术方法到类
for op_name in ['add', 'sub']:
    setattr(Foo, f'__{op_name}__', getattr(Foo, op_name))

方案2:通过元类实现动态查找

如果需要动态处理更多运算符不想提前枚举,可以通过元类实现,因为魔术方法查找的是类的属性,元类的__getattr__会响应类的属性查找:

class OpMeta(type):
    def __getattr__(cls, name):
        stripped = name.strip('_')
        if stripped in {'add', 'sub'}:
            return getattr(cls, stripped)
        raise AttributeError

class Foo(metaclass=OpMeta):
    def add(self, other):
        return 1 + other
    def sub(self, other):
        return 1 - other

2. IPython内核崩溃的问题

原因

hasattr(self, name)本身在属性不存在时会触发实例的__getattr__方法,你在__getattr__内部调用hasattr(self, name)会导致无限递归,最终栈溢出引发内核崩溃。

规避方案

不要在__getattr__内部通过hasattr访问当前实例的属性,你可以直接判断处理后的方法名是否在预定义的合法集合中(就是你最开始的写法)。如果一定要动态判断是否存在对应实现,直接访问类的属性字典绕过__getattr__触发逻辑:

def __getattr__(self, name):
    stripped = name.strip('_')
    # 直接从类的属性字典判断,不会触发__getattr__
    if stripped in self.__class__.__dict__:
        return getattr(self, stripped)
    raise AttributeError

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 10:24:01