精通 Python 运算符重载:实战指南
Python 运算符重载
了解如何使用 __add__、__lt__ 等特殊方法重新定义 Python 运算符行为,增强 OOP 设计。
Python 运算符重载
Python 内置运算符根据操作数类型表现不同。例如 + 对数字相加、对字符串连接、对列表合并。这种灵活性通过运算符重载实现——让你为自定义类赋予上下文特定的运算符含义。
以简单 Point 类为例,表示二维平面坐标。无特殊方法时,尝试相加两点会引发 TypeError:
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
p1 = Point(1, 2)
p2 = Point(2, 3)
print(p1+p2)
输出
Traceback (most recent call last): File "<string>", line 9, in <module> print(p1+p2) TypeError: unsupported operand type(s) for +: 'Point' and 'Point'
因 Python 不知道如何组合两个 Point 实例,抛出异常。运算符重载让我们自定义该行为。
Python 特殊方法
双下划线包围的方法——__init__、__str__、__add__ 等——称特殊方法或“dunder”方法。它们由 Python 运行时隐式调用,是运算符重载、容器协议等的挂钩点。
例如 __str__ 控制对象转为人类可读字符串的方式。默认打印对象显示内存地址,通常无用。重写 __str__ 让调试和日志更清晰:
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return '({0}, {1})'.format(self.x, self.y)
现在打印 Point 得到:
p1 = Point(2, 3)
print(p1)
输出
(2, 3)
str(p1) 和 format(p1) 也用同一表示,因 Python 内部调用 p1.__str__()。
重载 + 运算符
为 Point 对象自定义加法,实现 __add__:
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return '({0}, {1})'.format(self.x, self.y)
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
测试新行为:
p1 = Point(1, 2)
p2 = Point(2, 3)
print(p1 + p2)
输出
(3, 5)
底层 Python 执行 p1.__add__(p2),返回坐标求和的新 Point。
下表是其他算术运算符及需实现的特殊方法速查:
| 运算符 | 表达式 | 特殊方法 |
|---|---|---|
| 加法 | p1 + p2 | __add__(self, other) |
| 减法 | p1 - p2 | __sub__(self, other) |
| 乘法 | p1 * p2 | __mul__(self, other) |
| 幂 | p1 ** p2 | __pow__(self, other) |
| 除法 | p1 / p2 | __truediv__(self, other) |
| 地板除 | p1 // p2 | __floordiv__(self, other) |
| 取模 | p1 % p2 | __mod__(self, other) |
| 左移 | p1 << p2 | __lshift__(self, other) |
| 右移 | p1 >> p2 | __rshift__(self, other) |
| 位与 | p1 & p2 | __and__(self, other) |
| 位或 | p1 | p2 | __or__(self, other) |
| 位异或 | p1 ^ p2 | __xor__(self, other) |
| 位非 | ~p1 | __invert__(self) |
重载比较运算符
运算符重载不限于算术。比较运算符也可定制。例如按到原点距离比较点,重写 __lt__:
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return '({0}, {1})'.format(self.x, self.y)
def __lt__(self, other):
self_mag = self.x**2 + self.y**2
other_mag = other.x**2 + other.y**2
return self_mag < other_mag
用法:
p1 = Point(1, 1)
p2 = Point(-2, -3)
p3 = Point(1, -1)
print(p1 < p2) # True
print(p2 < p3) # False
print(p1 < p3) # False
其他比较方法模式类似:
| 运算符 | 表达式 | 特殊方法 |
|---|---|---|
| 小于 | p1 < p2 | __lt__(self, other) |
| 小于等于 | p1 <= p2 | __le__(self, other) |
| 等于 | p1 == p2 | __eq__(self, other) |
| 不等于 | p1 != p2 | __ne__(self, other) |
| 大于 | p1 > p2 | __gt__(self, other) |
| 大于等于 | p1 >= p2 | __ge__(self, other) |
谨慎定义这些方法,可让自定义对象自然参与算术和比较上下文,提升代码可读性和可维护性。
Python
- C++ 运算符重载实战指南:语法、方法、限制与代码示例
- 精通Python数据类型:实战指南
- 精通Python运算符:全面指南
- 精通Python Pass语句:实战指南
- 精通Python函数参数:位置、关键字与默认参数
- 精通 Python 字典:创建、操作与进阶技巧
- 精通 Python 继承:概念、语法与实战示例
- 精通 Python 迭代器:工作原理与自定义构建
- Python 闭包详解:嵌套函数如何捕获变量
- 精通 Python @property 装饰器:简洁、向后兼容的 Getter 与 Setter
- 精通 Python datetime:日期、时间与时区实战指南
- 精通 Python time.sleep():最佳实践、多线程与实战案例