是否可以在 Python 中覆盖 += ?
4 回答
是的,覆盖该__iadd__
方法。例子:
def __iadd__(self, other):
self.number += other.number
return self
除了上面答案中正确给出的内容之外,值得明确说明的是,何时__iadd__
被覆盖,x += y
操作不会以__iadd__
方法结束而结束。
相反,它以x = x.__iadd__(y)
. 换句话说,__iadd__
在实现完成之后,Python 将实现的返回值分配给您“添加到”的对象。
这意味着可以改变操作的左侧,以x += y
使最终的隐式步骤失败。考虑当您添加到列表中的内容时会发生什么:
>>> x[1] += y # x has two items
现在,如果您的__iadd__
实现(位于 的对象的方法x[1]
)错误地或故意删除了x[0]
列表开头的第一项( ),那么 Python 将运行您的__iadd__
方法)并尝试将其返回值分配给x[1]
. 它将不再存在(它将位于x[0]
),从而导致ÌndexError
.
或者,如果您在上述示例__iadd__
的开头插入一些内容x
,您的对象将位于 at x[2]
, not x[1]
,并且之前的 atx[0]
将位于 atx[1]
并被分配__iadd__
调用的返回值。
除非人们了解正在发生的事情,否则由此产生的错误可能是一场难以修复的噩梦。
除了重载__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.id
、y.id
和Resource.class_counter
具有什么值?
http://docs.python.org/reference/datamodel.html#emulating-numeric-types
例如,要执行语句 x += y,其中 x 是具有 __iadd__() 方法的类的实例,调用 x.__iadd__(y)。