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.
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.
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.
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.
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.
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
- Return self: Always return the modified object for chaining
- Modify in-place: Truly implement in-place behavior
- Type checking: Validate operands when necessary
- Fallback behavior: Consider implementing __mod__ too
- Document behavior: Clearly document any special cases
Source References
Author
List all Python tutorials.