是否可以在Python中覆盖+ =?
Answers:
是的,重写该__iadd__
方法。例:
def __iadd__(self, other):
self.number += other.number
return self
__add__
,则不一定要实施__iadd__
?我读了您链接的重复问题,但是我很困惑,因为我不明白您为什么要实现__add__
它,以便使对象发生变化
__iadd__
使用+ =吗?”
__iadd__
,它将__add__
在可用的情况下使用,通常就可以了。因此,在这种情况下,它a += b
等同于a = a + b
,它会为其分配一个新值,a
而不是更改a
自身。__iadd__
通常,单独使用是一种不错的优化方法,而不是您需要使用+=
运算符的方法。
__imul__
吗?
除了以上答案中正确给出的内容外,值得明确说明的__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
上面的例子中,你的目标将是x[2]
,不x[1]
和任何早于x[0]
现在将在x[1]
和被赋予的返回值__iadd__
调用。
除非人们了解发生了什么,否则产生的错误可能是修复的噩梦。
__iadd__
会这样设计吗?即,为什么它分配返回值而不是仅仅就地进行突变?
除了超载__iadd__
(记住要返回自身!)之外,您还可以回退__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
有哪些?
foo += bar
它可能意味着“使foo
引用的现有对象发生突变”或“分配foo
给由表达式生成的对象foo + bar
”。而究竟发生什么取决于是否foo
有__iadd__
方法。
http://docs.python.org/reference/datamodel.html#emulating-numeric-types
例如,要执行语句x + = y,其中x是具有__iadd __()方法的类的实例,则调用x .__ iadd __(y)。
__iadd__
如果您的类表示不可变的对象,则不应实现。在这种情况下,只需实现__add__
将用于替代的实现即可+=
。例如,您可以使用+=
不可变的类型(例如字符串和整数),而不能使用__iadd__
。