Python __imul__ Method

Complete guide to Python's __imul__ method covering in-place multiplication, operator overloading, and practical examples.

Python __imul__ Method

Python imul Method

Last modified April 8, 2025

This comprehensive guide explores Python’s imul method, the special method that implements in-place multiplication. We’ll cover basic usage, operator overloading, mutable vs immutable types, and practical examples.

Basic Definitions

The imul method is called to implement the in-place multiplication operation (*=). It should modify and return self when possible, but can return a new object if necessary.

Key characteristics: it modifies the object in-place when possible, returns the result (usually self), and is called for *= operations. If not implemented, Python falls back to mul followed by assignment.

Basic imul Implementation

Here’s a simple implementation showing how imul works with a custom class. The method modifies the object’s state and returns itself.

basic_imul.py

class Number: def init(self, value): self.value = value

def __imul__(self, other):
    self.value *= other
    return self

def __repr__(self):
    return f"Number({self.value})"

num = Number(5) num *= 3 print(num) # Output: Number(15)

This example shows a basic imul implementation that modifies the instance’s value attribute. The method returns self to allow chaining operations.

The *= operator calls imul, which updates the object’s state in-place. This is more efficient than creating a new object.

imul with Mutable Sequences

For mutable sequences like lists, imul performs in-place repetition. This example demonstrates the behavior with a custom sequence.

sequence_imul.py

class MyList: def init(self, items): self.items = list(items)

def __imul__(self, factor):
    self.items *= factor
    return self

def __repr__(self):
    return f"MyList({self.items})"

lst = MyList([1, 2]) lst *= 3 print(lst) # Output: MyList([1, 2, 1, 2, 1, 2])

This custom list class implements imul to multiply its contents in-place. The original object is modified rather than creating a new one.

The implementation delegates to the built-in list’s *= operation, which efficiently handles the repetition. This pattern is common for wrappers.

imul with Immutable Types

Immutable types can’t be modified in-place, so their imul must return a new object. This example shows the behavior difference.

immutable_imul.py

class ImmutableNumber: def init(self, value): self.value = value

def __imul__(self, other):
    return ImmutableNumber(self.value * other)

def __repr__(self):
    return f"ImmutableNumber({self.value})"

num = ImmutableNumber(5) num *= 3 print(num) # Output: ImmutableNumber(15) print(id(num)) # Shows a new object was created

Since immutable objects can’t change their state, imul returns a new instance. The original object remains unchanged, and the variable is reassigned.

This matches Python’s built-in behavior for immutable types like tuples, where *= creates a new object rather than modifying in-place.

Matrix Multiplication with imul

For mathematical objects like matrices, imul can implement in-place matrix multiplication. This example shows a simplified version.

matrix_imul.py

class Matrix: def init(self, data): self.data = data

def __imul__(self, other):
    if isinstance(other, (int, float)):
        # Scalar multiplication
        self.data = [[x * other for x in row] 
                    for row in self.data]
        return self
    # Matrix multiplication would go here
    raise TypeError("Unsupported operand type")

def __repr__(self):
    return f"Matrix({self.data})"

m = Matrix([[1, 2], [3, 4]]) m *= 2 print(m) # Output: Matrix([[2, 4], [6, 8]])

This matrix class implements scalar multiplication in-place through imul. The method checks the operand type and performs the appropriate operation.

For actual matrix multiplication, you would need to implement the full algorithm, but this shows the in-place modification pattern.

Combining imul with Other Operations

imul can be combined with other operations for complex behavior. This example shows a class that tracks multiplication history.

tracking_imul.py

class TrackingNumber: def init(self, value): self.value = value self.history = []

def __imul__(self, other):
    self.history.append((self.value, other))
    self.value *= other
    return self

def get_history(self):
    return self.history

def __repr__(self):
    return f"TrackingNumber({self.value})"

num = TrackingNumber(2) num *= 3 num *= 4 print(num) # Output: TrackingNumber(24) print(num.get_history()) # Output: [(2, 3), (6, 4)]

This class extends the basic number behavior by tracking all in-place multiplications. The history is stored in a list and updated during each operation.

The example demonstrates how imul can maintain additional state beyond just performing the mathematical operation. This is useful for debugging or auditing.

Best Practices

  • Modify in-place when possible: Follow Python’s mutable object conventions

  • Return self: Allows method chaining and matches built-in behavior

  • Handle different types: Check operand types and raise TypeError if needed

  • Consider immutability: Return new objects for immutable types

  • Document behavior: Clearly specify whether operation is in-place

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.

ad ad