Overriding "+=" in Python? (__iadd__() method)

PythonOperatorsOverriding

Python Problem Overview


Is it possible to override += in Python?

Python Solutions


Solution 1 - Python

Yes, override the __iadd__ method. Example:

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

Solution 2 - Python

In addition to what's correctly given in answers above, it is worth explicitly clarifying that when __iadd__ is overriden, the x += y operation does NOT end with the end of __iadd__ method.

Instead, it ends with x = x.__iadd__(y). In other words, Python assigns the return value of your __iadd__ implementation to the object you're "adding to", AFTER the implementation completes.

This means it is possible to mutate the left side of the x += y operation so that the final implicit step fails. Consider what can happen when you are adding to something that's within a list:

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

Now, if your __iadd__ implementation (a method of an object at x[1]) erroneously or on purpose removes the first item (x[0]) from the beginning of the list, Python will then run your __iadd__ method) & try to assign its return value to x[1]. Which will no longer exist (it will be at x[0]), resulting in an ÌndexError.

Or, if your __iadd__ inserts something to beginning of x of the above example, your object will be at x[2], not x[1], and whatever was earlier at x[0] will now be at x[1]and be assigned the return value of the __iadd__ invocation.

Unless one understands what's happening, resulting bugs can be a nightmare to fix.

Solution 3 - Python

In addition to overloading __iadd__ (remember to return self!), you can also fallback on __add__, as x += y will work like x = x + y. (This is one of the pitfalls of the += operator.)

>>> 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

It even trips up experts:

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

x = Resource()
y = Resource()

What values do you expect x.id, y.id, and Resource.class_counter to have?

Solution 4 - Python

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

> For instance, to execute the statement > x += y, where x is an instance of a > class that has an __iadd__() method, > x.__iadd__(y) is called.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEvan FosmarkView Question on Stackoverflow
Solution 1 - PythonJohn KugelmanView Answer on Stackoverflow
Solution 2 - PythonPetriView Answer on Stackoverflow
Solution 3 - PythonRoger PateView Answer on Stackoverflow
Solution 4 - PythonUnknownView Answer on Stackoverflow