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
| Operator | Method | Description | 
|---|---|---|
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.
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:
- The constructor 
__init__initializes thexandyattributes. - The 
__add__method adds thexvalues andyvalues separately and returns a newVectorobject. - The 
__str__method ensures that printing aVectorobject 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.
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:
- The 
__mul__method takes a scalar value and multiplies bothxandyvalues by it. - A new 
Vectorobject is returned with the scaled values. - 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.
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.
