在Python中覆盖“+ =”? (__iadd __()方法)
是否有可能重写+ =在Python中?
是的,覆盖__iadd__
方法。 例:
def __iadd__(self, other): self.number += other.number return self
除了重载__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 ax, bx 42 3 >>> old_id = id(a) >>> a += b >>> print ax 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
有什么值?
除了上面答案中正确给出的内容之外,值得明确的说明,当__iadd__
被覆盖时, x += y
操作不会以__iadd__
方法结束而结束。
相反,它以x = x.__iadd__(y)
。 换句话说,在实现完成后,Python会将__iadd__
实现的返回值分配给您要“添加到”的对象。
这意味着可以对x += y
操作的左侧进行变异,以便最终的隐式步骤失败。 考虑当你添加到列表中的东西时会发生什么:
>>> x[1] += y # x has two items
现在,如果你的__iadd__
实现( x[1]
的一个对象的方法)错误地或有意地从列表的开始处移除了第一个项目( x[0]
),Python将运行你的__iadd__
方法)尝试将其返回值分配给x[1]
。 这将不再存在(它将在x[0]
),导致一个ÌndexError
。
或者,如果你的__iadd__
在上面的例子的x
的开头插入了一些东西,你的对象将在x[2]
,而不是x[1]
,并且现在在x[0]
处的任何东西现在将在x[1]
和被分配了__iadd__
调用的返回值。
除非人们明白发生了什么事情,否则造成的错误可能是一个噩梦。
http://docs.python.org/reference/datamodel.html#emulating-numeric-types
例如,要执行语句x + = y,其中x是具有__iadd __()方法的类的实例,则调用x .__ iadd __(y)。