Joh*_*ica 107

是的,覆盖__iadd__方法.例:

def __iadd__(self, other):
    self.number += other.number
    return self    
Run Code Online (Sandbox Code Playgroud)

  • 如果您的类表示不可变对象,则不应实现`__iadd__`.在这种情况下,只需实现`__add__`,它将用于覆盖`+ =`.例如,你可以在不可变类型上使用`+ =`,例如字符串和整数,这是使用`__iadd__`无法完成的. (35认同)
  • @JosieThompson:如果你没有实现`__iadd__`那么它将使用`__add__`(如果可用),这通常很好.因此,在这种情况下,"a + = b"将等同于"a = a + b",它将新值赋给"a"而不是改变"a"本身.单独的`__iadd__`通常是一个很好的优化,而不是你需要使用`+ =`运算符. (8认同)

Pet*_*tri 21

除了上面的答案中正确给出的内容之外,值得明确说明当__iadd__重写时,x += y操作不会以__iadd__方法结束结束.

相反,它结束于x = x.__iadd__(y).换句话说,Python __iadd__在实现完成后将实现的返回值分配给您"添加到"的对象.

这意味着可以改变操作的左侧,x += y以便最后的隐式步骤失败.考虑当您添加到列表中的内容时会发生什么:

>>> x[1] += y # x has two items

现在,如果你的__iadd__实现(一个对象的方法x[1])错误地或有意地x[0]从列表的开头删除第一个item(),那么Python将运行你的__iadd__方法)并尝试将其返回值赋值给x[1].哪个将不再存在(它将在x[0]),从而产生一个ÌndexError.

或者,如果您在上面的示例的__iadd__开头插入了一些内容,那么您x的对象将处于x[2],而不是x[1]之前的任何内容,并且x[0]x[1]被赋予__iadd__调用的返回值.

除非人们理解正在发生的事情,否则产生的错误可能是一个噩梦.

  • @joel因为这就是它必须如何处理不可变类型,例如“str”和“int”,更重要的是“tuple”和“namedtuple”。 (5认同)
  • 你知道为什么 `__iadd__` 是这样设计的吗?即为什么它分配返回值而不是仅仅解决就地突变? (4认同)

小智 12

除了重载__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
Run Code Online (Sandbox Code Playgroud)

它甚至惹恼了专家:

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

x = Resource()
y = Resource()
Run Code Online (Sandbox Code Playgroud)

你期望什么样的价值观x.id,y.id以及Resource.class_counter有哪些?

  • 你的第二个例子与iadd或+ =无关.如果您使用self.class_counter = self.class_counter + 1,则会出现相同的结果.这只是一个范围问题,在使用Resource时使用self. (9认同)
  • @FogleBird:这是一个问题,因为`foo + = bar`可以表示"改变`foo`引用的现有对象"或"将`foo`分配给由表达式'foo + bar`"产生的对象.发生的事情取决于`foo`是否有`__iadd__`方法. (4认同)

Unk*_*own 5

http://docs.python.org/reference/datamodel.html#emulating-numeric-types

例如,要执行语句x + = y,其中x是具有__iadd __()方法的类的实例,则调用x .__ iadd __(y).