人人都会AI编程

运算符重载:__add__、__str__、__repr__

更新时间:2026-07-12

在 Python 中,运算符重载是指*通过定义特定的魔法方法,让自定义类的实例也能使用 +- 等内置运算符,或参与 str()print() 等内置功能**。这让你设计的类使用起来像 Python 内置类型一样自然。

下面重点讲解最常见、最实用的三个方法:addstrrepr


add:让对象支持 + 运算

  • 作用:当你对两对象使用 + 运算符时(a + b),Python 会自动调用 a.add(b),并将返回值作为表达式结果。
  • 适用场景:任何需要合并、拼接或求和的自定义类。例如向量相加、计数器合并、路径拼接等。
  • 示例:一个表示二维向量的类
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        """返回两个向量相加的结果(新对象)"""
        if not isinstance(other, Vector):
            return NotImplemented   # 如果 other 不是 Vector,交给 other 的 __radd__ 处理
        return Vector(self.x + other.x, self.y + other.y)

v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2        # 实际调用 v1.__add__(v2)
print(v3.x, v3.y)   # 输出 4 6
  • 设计要点:返回一个新对象(不可变对象语义)通常更安全,但也可改为 self.x += other.x 并返回 self,实现原地修改。注意用 isinstance 检查参数类型,避免意外行为。

str:用户友好字符串

  • 作用:当调用 str(obj)print(obj) 或用 f-string f"{obj}" 时触发,应返回易读、描述性的字符串,目的是给人看。
  • 默认行为:若未定义 str,Python 会转去调用 repr(因此即使没有 strprint 也有输出)。
class Vector:
    # ... 同上 __init__ 和 __add__ ...

    def __str__(self):
        return f"({self.x}, {self.y})"   # 简洁可读

v = Vector(5, 7)
print(v)          # 输出 (5, 7)
  • 原则print 的结果应该像“最终展示给终端用户的描述信息”,尽量避免包含调试细节(如内存地址)。

repr:开发者调试字符串

  • 作用:当调用 repr(obj)、在交互式解释器中直接输入对象名、或在调试时查看对象的字符串表示时触发。返回值应尽可能无歧义地代表对象内容,理想情况下是能够用 eval() 重建该对象的一份有效 Python 表达式。
  • 设计原则:“信息丰富且明确”,旨在帮助开发者识别对象内部状态。
class Vector:
    def __repr__(self):
        return f"Vector({self.x!r}, {self.y!r})"  # 用 !r 格式化内部值,确保 repr 嵌套正确

v = Vector(8, 9)
print(repr(v))     # 输出 Vector(8, 9)
# 在交互解释器直接敲 v,也会显示 Vector(8, 9)

注意示例中使用 !r 来格式化 self.xself.y,这样即使坐标是字符串类型,也能在 repr 中保留引号,保证 eval 的准确性。

  • 最佳实践:如果你只能实现一个,优先实现 repr(因为 str 找不到时会回退到 repr);如果两者都实现,则让 repr 面向开发者,str 面向用户。

三者协作示意

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)
    def __repr__(self):
        return f"Point({self.x}, {self.y})"
    def __str__(self):
        return f"坐标 ({self.x}, {self.y})"

p = Point(3, 4)
print(p)           # 调用 __str__ : 坐标 (3, 4)
p2 = p + Point(1, 2)
print(repr(p2))    # 调用 __repr__ : Point(4, 6)

通过合理重载这三个方法,自定义类可以无缝融入 Python 的打印、运算和调试生态,代码既优雅又自然。