ZetCode

Python __imod__ Method

Last modified April 8, 2025

This comprehensive guide explores Python's __imod__ method, the special method for in-place modulo operations. We'll cover basic usage, custom implementations, practical examples, and best practices.

Basic Definitions

The __imod__ method implements the in-place modulo operation (%=). It modifies the object in-place rather than creating a new object.

Key characteristics: it should return the modified object (usually self), performs the operation on the object itself, and is called when using the %= operator. If not implemented, Python falls back to __mod__.

Basic __imod__ Implementation

Here's a simple implementation showing how __imod__ works with a custom class. The example demonstrates basic in-place modulo behavior.

basic_imod.py
class ModuloNumber:
    def __init__(self, value):
        self.value = value
    
    def __imod__(self, other):
        self.value %= other
        return self
    
    def __repr__(self):
        return f"ModuloNumber({self.value})"

num = ModuloNumber(17)
num %= 5
print(num)  # Output: ModuloNumber(2)

This example shows a number wrapper class that implements in-place modulo. The __imod__ method modifies the instance's value and returns self to allow chaining.

The method first performs the modulo operation on the instance's value, then returns the modified instance. This is the standard pattern for in-place operations.

Custom Modulo Behavior

__imod__ can implement custom modulo behavior beyond simple arithmetic. This example shows a class that tracks modulo operations.

custom_modulo.py
class TrackedModulo:
    def __init__(self, value):
        self.value = value
        self.operations = []
    
    def __imod__(self, other):
        self.operations.append(f"Mod by {other}")
        self.value %= other
        return self
    
    def show_history(self):
        return self.operations

tracked = TrackedModulo(23)
tracked %= 5
tracked %= 3
print(tracked.value)  # 1
print(tracked.show_history())  # ['Mod by 5', 'Mod by 3']

This enhanced version keeps a history of all modulo operations performed. Each time %= is used, it records the operation before performing the calculation.

The method maintains the object's state while adding tracking functionality. This pattern is useful for debugging or auditing mathematical operations.

Matrix Modulo Operation

For more complex objects like matrices, __imod__ can perform element-wise operations. This example shows a simple matrix implementation.

matrix_modulo.py
class Matrix:
    def __init__(self, rows):
        self.rows = rows
    
    def __imod__(self, scalar):
        self.rows = [[x % scalar for x in row] 
                    for row in self.rows]
        return self
    
    def __repr__(self):
        return '\n'.join(str(row) for row in self.rows)

matrix = Matrix([[10, 20], [30, 40]])
matrix %= 7
print(matrix)
# Output:
# [3, 6]
# [2, 5]

This matrix class applies modulo to each element when the %= operator is used. The __imod__ method modifies the matrix in place.

The implementation uses list comprehension to apply the operation to each element. This is efficient and maintains the matrix structure.

Modulo With Validation

__imod__ can include validation logic to ensure operations are performed safely. This example validates the modulo operand.

validated_modulo.py
class SafeModulo:
    def __init__(self, value):
        self.value = value
    
    def __imod__(self, other):
        if other == 0:
            raise ValueError("Cannot modulo by zero")
        if not isinstance(other, (int, float)):
            raise TypeError("Modulo operand must be numeric")
        self.value %= other
        return self
    
    def __repr__(self):
        return f"SafeModulo({self.value})"

num = SafeModulo(25)
try:
    num %= 4
    print(num)  # SafeModulo(1)
    num %= 0    # Raises ValueError
except ValueError as e:
    print(e)

This safe modulo implementation checks for division by zero and ensures the operand is numeric. It raises appropriate exceptions for invalid cases.

The validation happens before the operation, preventing illegal states. This defensive programming approach makes the class more robust.

Modulo With Different Types

__imod__ can handle operations between different types. This example shows a class that works with both numbers and strings.

multi_type_modulo.py
class FlexibleModulo:
    def __init__(self, value):
        self.value = value
    
    def __imod__(self, other):
        if isinstance(other, str):
            self.value = self.value % (other,)
        else:
            self.value %= other
        return self
    
    def __str__(self):
        return str(self.value)

flex = FlexibleModulo(10)
flex %= 3
print(flex)  # 1

flex = FlexibleModulo("Result: %d")
flex %= 42
print(flex)  # Result: 42

This flexible class handles both numeric modulo and string formatting operations. The behavior changes based on the operand type.

When the operand is a string, it performs string formatting. With numbers, it does arithmetic modulo. This shows __imod__'s versatility.

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.