ZetCode

Python __add__ 方法

最后修改于 2025 年 4 月 8 日

本综合指南探讨了 Python 的 __add__ 方法,该方法是实现加法运算符 (+) 的特殊方法。我们将介绍基本用法、运算符重载、类型处理和实际示例。

基本定义

当对象使用 + 运算符时,会调用 __add__ 方法。它定义了当类的实例与其他对象相加时应如何表现。这是 Python 运算符重载机制的一部分。

主要特点:它接受 self 和另一个操作数作为参数,应返回加法的结果,并且可以为不支持的操作引发 NotImplemented。它支持自定义加法行为。

基本的 __add__ 实现

这是一个简单的实现,展示了 __add__ 如何与自定义类一起工作。此示例演示了两个对象之间的基本加法。

basic_add.py
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        if isinstance(other, Vector):
            return Vector(self.x + other.x, self.y + other.y)
        return NotImplemented

v1 = Vector(2, 4)
v2 = Vector(5, 1)
v3 = v1 + v2
print(f"Result: ({v3.x}, {v3.y})")  # Output: (7, 5)

这个 Vector 类通过 __add__ 实现向量加法。当两个 Vector 实例相加时,它返回一个包含求和分量的新 Vector。

NotImplemented 返回值表示不支持的操作。然后,Python 将尝试另一个操作数的 __radd__ 方法(如果可用)。

处理不同的类型

__add__ 可以通过检查 other 参数类型并实现适当的行为来处理不同类型的操作。

mixed_types.py
class Currency:
    def __init__(self, amount, currency_code):
        self.amount = amount
        self.code = currency_code
    
    def __add__(self, other):
        if isinstance(other, Currency):
            if self.code == other.code:
                return Currency(self.amount + other.amount, self.code)
            raise ValueError("Cannot add different currencies")
        elif isinstance(other, (int, float)):
            return Currency(self.amount + other, self.code)
        return NotImplemented

usd1 = Currency(50, "USD")
usd2 = Currency(75, "USD")
print((usd1 + usd2).amount)  # 125

try:
    eur = Currency(100, "EUR")
    usd1 + eur  # Raises ValueError
except ValueError as e:
    print(e)

这个 Currency 类允许与其他 Currency 对象(仅限相同货币)以及数字相加。它演示了类型检查和不同的行为。

该示例展示了如何实现业务规则(相同货币要求)并支持多种操作数类型,同时保持类型安全。

实现 __radd__ 以进行右加法

当左操作数不支持加法时,Python 会在右操作数上调用 __radd__。同时实现两者可以使操作具有交换性。

right_add.py
class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius
    
    def __add__(self, other):
        if isinstance(other, (int, float)):
            return Temperature(self.celsius + other)
        return NotImplemented
    
    def __radd__(self, other):
        return self.__add__(other)

t1 = Temperature(20)
t2 = 5 + t1  # Uses __radd__
t3 = t1 + 10  # Uses __add__
print(t2.celsius)  # 25
print(t3.celsius)  # 30

此 Temperature 类支持与任何一侧的数字相加。__radd__ 方法委托给 __add__ 以获得一致的行为。

如果没有 __radd__5 + t1 将会失败,因为整数不知道如何添加 Temperature 对象。这使得操作具有交换性。

使用 __iadd__ 进行原地加法

__iadd__ 方法实现 += 运算符以进行原地加法。为了提高效率,它应该修改并返回自身(如果可能)。

inplace_add.py
class ShoppingCart:
    def __init__(self):
        self.items = []
    
    def __add__(self, other):
        new_cart = ShoppingCart()
        new_cart.items = self.items.copy()
        if isinstance(other, ShoppingCart):
            new_cart.items.extend(other.items)
        elif isinstance(other, list):
            new_cart.items.extend(other)
        else:
            return NotImplemented
        return new_cart
    
    def __iadd__(self, other):
        if isinstance(other, ShoppingCart):
            self.items.extend(other.items)
        elif isinstance(other, list):
            self.items.extend(other)
        else:
            return NotImplemented
        return self

cart = ShoppingCart()
cart += ["apple", "banana"]  # Uses __iadd__
cart = cart + ["orange"]  # Uses __add__
print(cart.items)  # ['apple', 'banana', 'orange']

这个 ShoppingCart 展示了 __add__(创建新对象)和 __iadd__(修改现有对象)之间的区别。 += 在可用时使用 __iadd__

__iadd__ 应该返回 self 以匹配 Python 的原地操作语义。这允许链式操作并保持预期行为。

将自定义对象添加到内置类型

通过在该方法中实现适当的类型处理,__add__ 可以支持将自定义对象添加到 Python 内置类型。

custom_builtin.py
class Measurement:
    def __init__(self, value, unit):
        self.value = value
        self.unit = unit
    
    def __add__(self, other):
        if isinstance(other, Measurement):
            if self.unit == other.unit:
                return Measurement(self.value + other.value, self.unit)
            raise ValueError("Units must match")
        elif isinstance(other, (int, float)):
            return Measurement(self.value + other, self.unit)
        return NotImplemented
    
    def __radd__(self, other):
        return self.__add__(other)
    
    def __str__(self):
        return f"{self.value} {self.unit}"

m1 = Measurement(5, "kg")
m2 = Measurement(3, "kg")
print(m1 + m2)  # 8 kg
print(m1 + 2.5)  # 7.5 kg
print(10 + m2)  # 13 kg

这个 Measurement 类支持与其他 Measurements(相同单位)以及数字相加。__radd__ 启用了 number + Measurement 语法。

该示例展示了如何在提供自定义和内置类型灵活加法功能的同时,保持单位一致性。

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直撰写编程文章。到目前为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出所有 Python 教程