ZetCode

Python __isub__ Method

Last modified April 8, 2025

This comprehensive guide explores Python's __isub__ method, the special method for in-place subtraction. We'll cover basic usage, operator overloading, mutable vs immutable types, and practical examples.

Basic Definitions

The __isub__ method implements the in-place subtraction operation (-=). It modifies the object's value without creating a new object.

Key characteristics: it should modify and return self, is called when -= is used, and typically provides better performance than regular subtraction for mutable objects.

Basic __isub__ Implementation

Here's a simple implementation showing how __isub__ works with a custom class. The method modifies the instance in place.

basic_isub.py
class Counter:
    def __init__(self, value):
        self.value = value
    
    def __isub__(self, other):
        self.value -= other
        return self
    
    def __repr__(self):
        return f"Counter({self.value})"

c = Counter(10)
c -= 3
print(c)  # Counter(7)

This example shows a simple counter class that implements in-place subtraction. When -= is used, __isub__ modifies the instance's value and returns self.

The method must return self to work correctly with chained operations and to match Python's expected behavior for in-place operations.

__isub__ with Mutable Objects

For mutable objects, __isub__ can provide significant performance benefits by avoiding the creation of new objects during subtraction.

mutable_isub.py
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __isub__(self, other):
        self.x -= other.x
        self.y -= other.y
        return self
    
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(5, 7)
v2 = Vector(2, 3)
v1 -= v2
print(v1)  # Vector(3, 4)

This vector class implements in-place vector subtraction. The operation modifies the original vector instead of creating a new one, which is more efficient.

For large objects or frequent operations, this can significantly reduce memory usage and improve performance compared to regular subtraction.

__isub__ with Immutable Objects

Immutable objects can't be modified in place, so their __isub__ typically returns a new object, similar to regular subtraction.

immutable_isub.py
class ImmutablePoint:
    def __init__(self, x, y):
        self._x = x
        self._y = y
    
    @property
    def x(self):
        return self._x
    
    @property
    def y(self):
        return self._y
    
    def __isub__(self, other):
        return ImmutablePoint(self.x - other, self.y - other)
    
    def __repr__(self):
        return f"Point({self.x}, {self.y})"

p = ImmutablePoint(8, 6)
p -= 2
print(p)  # Point(6, 4)

This immutable point class returns a new instance when __isub__ is called. The original object remains unchanged, maintaining immutability.

Note that for immutable objects, a -= b behaves the same as a = a - b, just with potentially different implementation details.

__isub__ with Different Types

__isub__ can handle operations with different types, providing flexible in-place subtraction behavior.

type_handling_isub.py
class Measurement:
    def __init__(self, value, unit='m'):
        self.value = value
        self.unit = unit
    
    def __isub__(self, other):
        if isinstance(other, (int, float)):
            return Measurement(self.value - other, self.unit)
        elif isinstance(other, Measurement):
            if self.unit == other.unit:
                return Measurement(self.value - other.value, self.unit)
            raise ValueError("Units must match")
        raise TypeError("Unsupported type")
    
    def __repr__(self):
        return f"{self.value}{self.unit}"

m = Measurement(10)
m -= 2.5
print(m)  # 7.5m

This measurement class handles subtraction with both numbers and other measurements. It includes unit checking when subtracting measurements.

The implementation shows how to make __isub__ work with multiple types while maintaining proper error checking and type safety.

__isub__ in Built-in Types

Python's built-in types like lists implement __isub__ for in-place operations. Here's how it works with lists.

builtin_isub.py
numbers = [1, 2, 3, 4, 5]
numbers -= [3, 4]  # Equivalent to numbers.extend([3, 4])
print(numbers)  # [1, 2, 3, 4, 5, 3, 4]

# For sets, -= performs difference_update
s = {1, 2, 3, 4, 5}
s -= {3, 4}
print(s)  # {1, 2, 5}

For lists, -= performs an extend operation (which might be surprising). For sets, it performs a difference update, removing elements.

This demonstrates how different built-in types implement __isub__ differently based on their semantics. Always check the type's documentation.

Best Practices

Source References

Author

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.