Operator Overloading in Python

Python allows operator overloading, which means that we can define how operators like +, -, *, and others behave for user-defined classes. This allows objects of custom classes to respond to operators in a meaningful way, just like built-in types such as integers and lists.

What is Operator Overloading?

Operator overloading allows us to define special methods in a class to modify the behavior of built-in operators. For example, using + between two numbers adds them, but when used with strings, it concatenates them. Similarly, we can define how the + operator should work for objects of our own class.

Common Special Methods for Operator Overloading

OperatorMethodDescription
Addition (+)__add__(self, other)Defines behavior for the + operator.
Subtraction (-)__sub__(self, other)Defines behavior for the - operator.
Multiplication (*)__mul__(self, other)Defines behavior for the * operator.
Division (/)__truediv__(self, other)Defines behavior for the / operator.
Floor Division (//)__floordiv__(self, other)Defines behavior for the // operator.
Modulus (%)__mod__(self, other)Defines behavior for the % operator.
Power (**)__pow__(self, other)Defines behavior for the ** operator.
Less Than (<)__lt__(self, other)Defines behavior for the < operator.
Greater Than (>)__gt__(self, other)Defines behavior for the > operator.
Equality (==)__eq__(self, other)Defines behavior for the == operator.
String Representation__str__(self)Defines string representation of an object for print().

Examples

1. Overloading the Addition Operator (+)

Let’s define a class Vector that represents a point in a 2D space. We will overload the + operator so that when two Vector objects are added, their respective x and y components are added together.

</>
Copy
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __str__(self):
        return f"Vector({self.x}, {self.y})"

# Creating two Vector objects
v1 = Vector(2, 3)
v2 = Vector(4, 5)

# Using the overloaded + operator
result = v1 + v2

print(result)

Output:

Vector(6, 8)

Here’s what happens:

  1. The constructor __init__ initializes the x and y attributes.
  2. The __add__ method adds the x values and y values separately and returns a new Vector object.
  3. The __str__ method ensures that printing a Vector object returns a readable string.

2. Overloading the Multiplication Operator (*)

Now, let’s overload the * operator so that multiplying a Vector by a number scales both components.

</>
Copy
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    
    def __str__(self):
        return f"Vector({self.x}, {self.y})"

# Creating a Vector object
v = Vector(3, 4)

# Scaling the vector by 2
scaled_vector = v * 2

print(scaled_vector)

Output:

Vector(6, 8)

Here’s what happens:

  1. The __mul__ method takes a scalar value and multiplies both x and y values by it.
  2. A new Vector object is returned with the scaled values.
  3. The __str__ method is used to print the result.

3. Handling Errors in Operator Overloading

If we try to use an overloaded operator incorrectly, Python will raise an error. Let’s see what happens if we try to add a Vector object to an integer.

</>
Copy
try:
    v1 = Vector(2, 3)
    result = v1 + 5  # This will cause an error
except TypeError as e:
    print("Error:", e)

Output:

Error: unsupported operand type(s) for +: 'Vector' and 'int'

Since our __add__ method expects another Vector, trying to add an integer raises an error. We can modify the method to handle this case properly.