在Python中重载“+=”运算符?(__iadd__()方法)

94 投票
4 回答
75388 浏览
提问于 2025-04-15 12:30

在Python中,可以重写+=这个操作符吗?

4 个回答

15

除了重载 __iadd__ 方法(记得要返回 self!),你还可以使用 __add__ 方法,因为 x += y 实际上就像是 x = x + y。这就是 += 操作符的一个常见误区。

>>> class A(object):
...   def __init__(self, x):
...     self.x = x
...   def __add__(self, other):
...     return A(self.x + other.x)
>>> a = A(42)
>>> b = A(3)
>>> print a.x, b.x
42 3
>>> old_id = id(a)
>>> a += b
>>> print a.x
45
>>> print old_id == id(a)
False

这甚至会让一些专家感到困惑:

class Resource(object):
  class_counter = 0
  def __init__(self):
    self.id = self.class_counter
    self.class_counter += 1

x = Resource()
y = Resource()

你期望 x.idy.idResource.class_counter 的值是什么呢?

47

除了上面答案中正确提到的内容外,还需要明确说明,当你重写了 __iadd__ 方法时,x += y 这个操作并不是在 __iadd__ 方法结束时就结束了。

实际上,它是在 x = x.__iadd__(y) 这一步结束。换句话说,Python 会在你的 __iadd__ 方法执行完后,把你实现的返回值赋给你“添加到”的那个对象。

这意味着你可以改变 x += y 左边的对象,导致最后的隐式步骤失败。想象一下,当你在给一个列表中的元素加东西时,会发生什么:

>>> x[1] += y # x 有两个元素

现在,如果你的 __iadd__ 实现(也就是 x[1] 的一个方法)错误地或者故意地把列表的第一个元素(x[0])删除了,Python 会运行你的 __iadd__ 方法,然后尝试把返回值赋给 x[1]。但此时 x[1] 已经不存在了(它会变成 x[0]),这就会导致一个 IndexError 错误。

或者,如果你的 __iadd__ 方法在上面的例子中往 x 的开头插入了东西,那么你的对象会在 x[2],而不是 x[1],之前在 x[0] 的东西现在会在 x[1],并被赋值为 __iadd__ 调用的返回值。

如果不理解发生了什么,导致的错误可能会让人头疼不已。

155

是的,可以重写 __iadd__ 方法。下面是一个例子:

def __iadd__(self, other):
    self.number += other.number
    return self    

撰写回答