Python __matmul__ Method
Last modified April 8, 2025
This comprehensive guide explores Python's __matmul__ method, the
special method that implements matrix multiplication. We'll cover basic usage,
NumPy integration, custom implementations, and practical examples.
Basic Definitions
The __matmul__ method implements the matrix multiplication
operation (@) in Python. Introduced in Python 3.5, it provides
a dedicated operator for matrix operations distinct from element-wise
multiplication.
Key characteristics: it must accept two operands (self and other), should return
the result of matrix multiplication, and is invoked when using the @
operator. It's commonly used in numerical computing libraries like NumPy.
Basic __matmul__ Implementation
Here's a simple implementation showing how to use __matmul__ in a
custom class. This example creates a basic 2x2 matrix class with matrix
multiplication support.
class Matrix:
def __init__(self, data):
self.data = data
def __matmul__(self, other):
if len(self.data[0]) != len(other.data):
raise ValueError("Incompatible matrix dimensions")
result = [[0 for _ in range(len(other.data[0]))]
for _ in range(len(self.data))]
for i in range(len(self.data)):
for j in range(len(other.data[0])):
for k in range(len(other.data)):
result[i][j] += self.data[i][k] * other.data[k][j]
return Matrix(result)
def __repr__(self):
return str(self.data)
A = Matrix([[1, 2], [3, 4]])
B = Matrix([[5, 6], [7, 8]])
print(A @ B) # [[19, 22], [43, 50]]
This example shows the standard matrix multiplication algorithm. The
__matmul__ method checks dimension compatibility, performs the
calculation, and returns a new Matrix instance with the result.
The implementation uses nested loops to compute the dot product of rows and
columns. The @ operator provides cleaner syntax than calling a
method like multiply().
NumPy Matrix Multiplication
NumPy's ndarray uses __matmul__ for matrix
multiplication. This example demonstrates NumPy's implementation which is
optimized for performance.
import numpy as np A = np.array([[1, 2], [3, 4]]) B = np.array([[5, 6], [7, 8]]) # Using @ operator (calls __matmul__) result = A @ B print(result) # Equivalent using matmul function result = np.matmul(A, B) print(result) # Note: * does element-wise multiplication print(A * B) # Different from @
NumPy's implementation is highly optimized using C and Fortran libraries. The
@ operator provides a clean syntax for matrix operations while
clearly distinguishing from element-wise multiplication (*).
For large matrices, NumPy's implementation is orders of magnitude faster than pure Python. It also handles broadcasting and higher-dimensional arrays.
Vector Multiplication
The __matmul__ method can also implement vector dot products.
This example shows a Vector class with dot product support via @.
class Vector:
def __init__(self, components):
self.components = components
def __matmul__(self, other):
if len(self.components) != len(other.components):
raise ValueError("Vectors must have same length")
return sum(a * b for a, b in zip(self.components, other.components))
def __repr__(self):
return f"Vector({self.components})"
v1 = Vector([1, 2, 3])
v2 = Vector([4, 5, 6])
print(v1 @ v2) # 32 (1*4 + 2*5 + 3*6)
This implementation calculates the dot product of two vectors. The
__matmul__ method checks vector lengths match, then computes the
sum of component-wise products.
Using @ for dot products provides mathematical clarity, though
some libraries use it exclusively for matrix-matrix multiplication.
Chained Matrix Operations
The @ operator can be chained like other arithmetic operators.
This example demonstrates multiple matrix multiplications in one expression.
import numpy as np A = np.random.rand(3, 3) B = np.random.rand(3, 3) C = np.random.rand(3, 3) # Chained matrix multiplication result = A @ B @ C # Equivalent to: temp = A @ B result = temp @ C print(result.shape) # (3, 3)
Matrix multiplication is associative, so chaining operations with @
works as expected. The operations are performed left-to-right, with each
@ calling __matmul__ on its left operand.
NumPy optimizes such chains internally when possible, reducing temporary allocations. The syntax remains clean regardless of operation count.
Custom Linear Transformation
This example shows how __matmul__ can implement linear
transformations, applying a transformation matrix to a vector.
class Transform:
def __init__(self, matrix):
self.matrix = matrix
def __matmul__(self, vector):
if len(self.matrix[0]) != len(vector):
raise ValueError("Incompatible dimensions")
return [sum(m * v for m, v in zip(row, vector))
for row in self.matrix]
def __repr__(self):
return f"Transform({self.matrix})"
# Rotation matrix (45 degrees)
theta = 45 * (3.14159 / 180)
rot = Transform([
[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]
])
point = [1, 0] # Point on x-axis
transformed = rot @ point
print(transformed) # [0.7071, 0.7071] (45° rotated)
This implementation applies a transformation matrix to a vector using the
@ operator. The __matmul__ method performs the
matrix-vector multiplication.
The example shows a rotation transformation, but any linear transformation can be represented this way. The clean syntax makes mathematical code more readable.
Best Practices
- Follow mathematical conventions: Implement proper matrix multiplication rules
- Check dimensions: Validate input shapes match multiplication requirements
- Return appropriate type: Maintain consistent return types with inputs
- Document behavior: Clearly specify supported operations and dimensions
- Consider performance: For complex operations, optimize or use libraries
Source References
Author
List all Python tutorials.