In Python, operator overloading is a feature that allows you to define the behavior of operators (like +
, -
, *
, ==
, etc.) for user-defined classes. By overloading operators, you can make instances of your classes behave like built-in types when they are used with operators.Operator overloading is a powerful tool that enhances the expressiveness of your classes and allows them to interact naturally with Python's syntax.In this guide, we will explore how operator overloading works in Python, how to implement it, and examine some common examples.
Operator overloading, also known as operator ad-hoc polymorphism, allows you to define or redefine the behavior of operators for user-defined classes. This means that you can make your custom objects behave like built-in objects when using operators.
For example, the +
operator typically adds two numbers together. But what if you want to add two ComplexNumber objects or two Point objects? In such cases, you can overload the +
operator to suit your class-specific requirements.
In Python, operator overloading is implemented by defining special methods in your class. These methods are also called magic methods or dunder methods (due to the double underscores), and they are called implicitly when the corresponding operator is used.
Here are some common operator overloading methods:
__add__(self, other)
for the +
operator__sub__(self, other)
for the -
operator__mul__(self, other)
for the *
operator__truediv__(self, other)
for the /
operator__eq__(self, other)
for the ==
operator__lt__(self, other)
for the <
operator+
OperatorLet’s start with a simple example: overloading the +
operator to add two Point
objects, where each point is defined by its x and y coordinates.
+
Operator for Point Class
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# Overloading the '+' operator
def __add__(self, other):
# Adding the x and y coordinates of two points
return Point(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Point({self.x}, {self.y})"
# Creating two Point objects
point1 = Point(2, 3)
point2 = Point(4, 5)
# Adding two Point objects
result = point1 + point2 # This calls point1.__add__(point2)
# Output the result
print(result) # Output: Point(6, 8)
__add__
method is overloaded to define how the +
operator behaves when applied to two Point
objects.__repr__
method is used to provide a user-friendly string representation of the Point
object.point1 + point2
is executed, Python internally calls point1.__add__(point2)
, which returns a new Point
object with the summed coordinates.==
OperatorYou can also overload comparison operators like ==
to compare two objects of your class. Let's create a Rectangle
class and overload the ==
operator to compare the areas of two rectangles.
==
Operator for Rectangle Class
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
# Overloading the '==' operator
def __eq__(self, other):
# Compare the area of two rectangles
return (self.width * self.height) == (other.width * other.height)
def __repr__(self):
return f"Rectangle({self.width}, {self.height})"
# Creating two Rectangle objects
rect1 = Rectangle(4, 5)
rect2 = Rectangle(2, 10)
# Comparing two Rectangle objects
print(rect1 == rect2) # Output: True (since both have an area of 20)
__eq__
method is overloaded to define how the ==
operator works when comparing two Rectangle
objects.width * height
.*
OperatorLet’s look at a more complex example where we overload the *
operator to scale a Vector
object by a scalar value.
*
Operator for Vector Class
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
# Overloading the '*' operator for scalar multiplication
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
# Creating a Vector object
vec = Vector(3, 4)
# Scaling the vector by a scalar value
scaled_vec = vec * 2 # This calls vec.__mul__(2)
# Output the result
print(scaled_vec) # Output: Vector(6, 8)
__mul__
method is overloaded to allow scalar multiplication. When vec * 2
is executed, Python calls vec.__mul__(2)
, which scales the vector's coordinates by 2.Here’s a list of common operators and the corresponding magic methods you can overload in Python:
Operator | Magic Method | Example Usage |
---|---|---|
+ |
__add__(self, other) |
a + b |
- |
__sub__(self, other) |
a - b |
* |
__mul__(self, other) |
a * b |
/ |
__truediv__(self, other) |
a / b |
// |
__floordiv__(self, other) |
a // b |
% |
__mod__(self, other) |
a % b |
** |
__pow__(self, other) |
a ** b |
== |
__eq__(self, other) |
a == b |
!= |
__ne__(self, other) |
a != b |
< |
__lt__(self, other) |
a < b |
> |
__gt__(self, other) |
a > b |
<= |
__le__(self, other) |
a <= b |
>= |
__ge__(self, other) |
a >= b |
[] |
__getitem__(self, key) |
a[key] |
[]= |
__setitem__(self, key, value) |
a[key] = value |
Let’s now use operator overloading in a more real-world example: adding two complex numbers.
+
Operator for Complex Numbers
class ComplexNumber:
def __init__(self, real, imag):
self.real = real
self.imag = imag
# Overloading the '+' operator
def __add__(self, other):
return ComplexNumber(self.real + other.real, self.imag + other.imag)
def __repr__(self):
return f"ComplexNumber({self.real}, {self.imag})"
# Creating two ComplexNumber objects
num1 = ComplexNumber(3, 2)
num2 = ComplexNumber(1, 7)
# Adding two ComplexNumber objects
result = num1 + num2 # This calls num1.__add__(num2)
# Output the result
print(result) # Output: ComplexNumber(4, 9)
__add__
method allows us to add two ComplexNumber
objects. The real parts and imaginary parts of the complex numbers are added separately.