直接用+报错是因为Python未定义自定义类的运算符行为,必须显式实现__add__等魔法方法;加减乘除对应__add__、__sub__、__mul__、__truediv__,需返回新对象、处理类型兼容性并正确支持反向运算。

为什么直接用 + 会报错:TypeError: unsupported operand type(s)
当你对两个自定义类实例写 a + b 却没定义任何特殊方法时,Python 根本不知道怎么算——它不会自动把属性加起来,也不会抛个友好提示,而是直接扔出 TypeError: unsupported operand type(s) for +: 'MyClass' and 'MyClass'。这不是 bug,是 Python 的明确设计:运算符重载必须显式声明。
必须实现哪些魔法方法:从 __add__ 到 __truediv__
加减乘除对应的标准双目运算符方法是:
-
+→__add__(self, other)(返回新对象,别改self) -
-→__sub__(self, other) -
*→__mul__(self, other) -
/→__truediv__(self, other)(注意不是__div__,那是 Python 2 的)
这些方法都得返回一个值(通常是同类新实例),如果无法处理 other 类型,应返回 NotImplemented(不是 NotImplementedError!),让 Python 尝试反向方法(如 __radd__)或报错。
容易踩的坑:类型检查、可变性与反向方法
常见错误不是忘了写方法,而是写了但不健壮:
立即学习“Python免费学习笔记(深入)”;
- 硬编码假设
other是同类型——实际可能传入int或float,需用isinstance(other, (int, float))或hasattr(other, 'value')做兼容 - 在
__add__里直接修改self.x += other.x——这破坏了不可变习惯,也导致链式运算出错(a + b + c中a被意外改掉) - 只实现了
__add__,但用户写了5 + obj——这时调用的是int.__add__,它不认识你的类,所以必须补__radd__(self, other)并让它等价于self.__add__(other) - 除法返回
int却没处理ZeroDivisionError,尤其当other是自定义类且其“除数”为 0 时
一个最小可行示例:带数值字段的 Vector2D
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
<pre class="brush:php;toolbar:false;">def __add__(self, other):
if isinstance(other, Vector2D):
return Vector2D(self.x + other.x, self.y + other.y)
elif isinstance(other, (int, float)):
return Vector2D(self.x + other, self.y + other)
return NotImplemented
def __radd__(self, other):
return self.__add__(other) # 支持 3 + v
def __mul__(self, other):
if isinstance(other, (int, float)):
return Vector2D(self.x * other, self.y * other)
return NotImplemented
def __repr__(self):
return f"Vector2D({self.x}, {self.y})"用法:
v1 = Vector2D(1, 2) v2 = Vector2D(3, 4) print(v1 + v2) # Vector2D(4, 6) print(2 * v1) # Vector2D(2, 4) print(5 + v1) # Vector2D(6, 7)
真正难的不是写这几个方法,而是想清楚:你的类在数学上“应该”怎么参与运算?比如 Matrix 的 * 是矩阵乘而非逐元素乘,Money 类做加法时是否要校验币种一致——这些语义约束,比语法更关键。


















