Python中算术运算符+、-、等通过双下划线魔法方法重载:__add__对应+,__sub__对应-,__mul__对应,__truediv__对应/,__floordiv__对应//,__mod__对应%,反向运算需__radd__等,就地运算用__iadd__等,比较方法需成对实现且返回布尔值。

Python里哪些魔法方法对应算术运算
重载 +、-、* 这类运算符,靠的是以双下划线开头和结尾的“魔法方法”,不是随便起名。写错名字就完全不生效,连报错都不会有——它只是默默走默认逻辑。
常见对应关系要记准:__add__ 对应 +,__sub__ 对应 -,__mul__ 对应 *,__truediv__ 对应 /,__floordiv__ 对应 //,__mod__ 对应 %。注意 __div__ 在 Python 3 里已废弃,用 __truediv__。
- 反向运算(比如
2 + obj而非obj + 2)需实现__radd__等,否则可能抛TypeError - 如果只实现
__add__但返回NotImplemented(不是异常!是内置常量),Python 会自动尝试调用右操作数的__radd__ -
__iadd__等就地运算方法不写的话,+=会退化为先调__add__再赋值,可能影响性能或对象身份
比较运算符必须成对实现才安全
只写 __eq__ 不写 __ne__,或者只写 __lt__ 不写 __le__,很容易踩坑。Python 不会自动推导补全,而且默认的 != 行为是 not ==,但前提是 __eq__ 明确返回了布尔值;如果它返回 NotImplemented,!= 就直接 fallback 到内存地址比较。
-
__eq__和__ne__必须都实现,且逻辑互逆;否则在集合、字典中做成员判断时行为不可控 - 想支持完整排序(如
sorted()或max()),至少得有__lt__;仅靠__gt__是不够的 - 从 Python 3.7 开始,
@functools.total_ordering装饰器能帮你省事:只要实现__eq__加一个核心比较方法(如__lt__),其余自动补全
重载时最容易被忽略的返回值类型
魔法方法的返回值类型决定了后续链式操作是否成立。比如 __add__ 返回 int,那 obj + 1 + 2 就没问题;但如果返回 None 或没写 return,第二步加法就会报 TypeError: unsupported operand type(s)。
立即学习“Python免费学习笔记(深入)”;
- 所有算术魔法方法都应该返回新对象(不可变类型惯例)或
self(可变类型用__iadd__时);绝不能静默失败 - 比较方法必须返回
True或False,返回1/0或其他真值在某些上下文(如assert)里看似正常,但违反协议,可能引发隐晦问题 - 如果不确定要不要支持某类操作数(比如只接受
int,不接受float),在方法开头用isinstance(other, int)判断,不匹配就 returnNotImplemented,别 raise 异常
自定义类参与内置函数时的兼容性陷阱
sum()、max()、min()、sorted() 这些函数内部会触发特定魔法方法,但它们的调用逻辑和普通运算符不同。比如 sum([a, b, c]) 默认以 0 为起点调 0 + a,所以你的类若想被 sum 正确处理,__radd__ 必须能处理 int 左操作数。
-
sum()要求类实现__radd__(因为起点是0),且该方法不能假设左操作数一定是同类型 -
sorted()默认用__lt__,但如果你传了key参数,就绕过所有比较方法,此时重载无效 -
len()调的是__len__,不是算术或比较方法,但它常和数值类一起出现,容易漏写导致TypeError: object of type 'X' has no len()
最麻烦的不是写不出来,而是写了一半——比如实现了 __add__ 却忘了 __radd__,结果在表达式左边出现内置类型时突然失效,还查不出原因。


















