Complete guide to Python's __iadd__ method covering in-place addition, operator overloading, and mutable objects.
Last modified April 8, 2025
This comprehensive guide explores Python’s iadd method, the special method that implements in-place addition with the += operator. We’ll cover basic usage, mutable vs immutable types, and practical examples.
The iadd method implements the in-place addition operation (+=). It should modify the object in-place and return the result (usually self).
Key characteristics: it modifies the object directly, returns self for mutable objects, and can return a new object for immutable types. It’s called when using the += operator.
Here’s a simple implementation showing how iadd works with a custom class. This demonstrates the basic behavior of in-place addition.
basic_iadd.py
class Accumulator: def init(self, value): self.value = value
def __iadd__(self, other):
self.value += other
return self
def __repr__(self):
return f"Accumulator({self.value})"
acc = Accumulator(5) acc += 3 print(acc) # Accumulator(8)
This example shows a simple accumulator that adds values in-place. The iadd method modifies the instance’s value and returns self.
The += operator calls iadd if available, falling back to add if not implemented. This method should return self for proper chaining.
The behavior of iadd differs between mutable and immutable objects. Lists implement it to modify in-place, while tuples don’t have it.
mutable_immutable.py
lst = [1, 2, 3] print(id(lst)) # Original ID lst += [4, 5] print(lst) # [1, 2, 3, 4, 5] print(id(lst)) # Same ID
tup = (1, 2, 3) print(id(tup)) # Original ID tup += (4, 5) print(tup) # (1, 2, 3, 4, 5) print(id(tup)) # Different ID
Lists modify themselves in-place, keeping the same ID. Tuples create a new object since they’re immutable. This shows how += behaves differently.
For immutable types, Python falls back to add when iadd isn’t available, creating a new object instead of modifying in-place.
We can implement custom in-place addition logic for complex objects. This example shows a Vector class with += operation.
vector_iadd.py
class Vector: def init(self, x, y): self.x = x self.y = y
def __iadd__(self, other):
if isinstance(other, Vector):
self.x += other.x
self.y += other.y
else:
self.x += other
self.y += other
return self
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2) v1 += Vector(3, 4) print(v1) # Vector(4, 6)
v1 += 5 print(v1) # Vector(9, 11)
This Vector class supports += with both Vector objects and scalars. The iadd method handles both cases and modifies the instance.
The method checks the type of the right operand to determine whether to do component-wise or scalar addition. It always returns self for chaining.
iadd can include side effects beyond just modification. This example tracks how many times an object has been modified.
side_effects.py
class Counter: def init(self, value): self.value = value self.mod_count = 0
def __iadd__(self, other):
self.value += other
self.mod_count += 1
return self
def __repr__(self):
return f"Counter(value={self.value}, mods={self.mod_count})"
c = Counter(10) c += 5 c += 3 print(c) # Counter(value=18, mods=2)
This Counter class increments a modification counter each time += is used. The iadd method updates both the value and the counter.
This pattern is useful for auditing changes or implementing change tracking systems where you need to know how often an object has been modified.
When subclassing, you might need to extend iadd behavior. This example shows how to properly implement it in a hierarchy.
inheritance.py
class Base: def init(self, value): self.value = value
def __iadd__(self, other):
self.value += other
return self
class Derived(Base): def iadd(self, other): print(“Before addition:”, self.value) super().iadd(other) print(“After addition:”, self.value) return self
d = Derived(10) d += 5
The Derived class extends the += behavior by adding logging while still using the parent class’s addition logic. It calls super() to delegate.
This pattern maintains the parent’s behavior while adding new functionality. The method still returns self to support proper operator chaining.
Return self: For mutable objects, return self for proper chaining
Modify in-place: Actually modify the object rather than creating new
Handle different types: Consider type checking for right operand
Document behavior: Clearly document any special += logic
Consider immutability: For immutable types, implement add instead
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.