Operator Overloading in Python
Operator overloading in Python allows same operator to work in different ways depending on data type.
- Python built-in data types allow + operator can add numbers, join strings or merge lists and * operator can be used to repeat instances of a string.
- Python also allows to do operator overloading for user defined classes by writing methods like
__add__(),__mul__(), __sub__(),, __lt__(), __gt__() and __eq__() to make objects work for operators like +, *, -, <, > and == respectively. - We cannot override or change the operator behavior of built-in types (like
int,str,list) globally; but we can subclass them (or define your own class) and implement the special methods
This example shows how built-in operators like + and * work differently depending on the data type.
# + operator for integers
print(1 + 2)
# + operator for strings (concatenation)
print("Geeks" + "For")
# * operator for numbers
print(3 * 4)
# * operator for strings (repetition)
print("Geeks" * 4)
Output
3 GeeksFor 12 GeeksGeeksGeeksGeeks
Operator Overloading for User Defined Types
When we use an operator on user-defined objects, Python doesn’t know how to handle it. To make operators work with custom classes, Python provides special methods (also called magic methods).
+ operator -> calls __add__(self, other)
- operator -> calls __sub__(self, other)
== operator -> calls __eq__(self, other)
So, when we write obj1 + obj2, internally Python calls:
obj1.__add__(obj2)
If this method is defined in the class, operator overloading works.
Example 1: This code shows how to overload the + operator for integers and strings inside a custom class.
class A:
def __init__(self, a):
self.a = a
# define behavior of +
def __add__(self, o):
return self.a + o.a
ob1 = A(1)
ob2 = A(2)
ob3 = A("Geeks")
ob4 = A("For")
print(ob1 + ob2) # integer addition
print(ob3 + ob4) # string concatenation
# actual working (internally)
print(A.__add__(ob1, ob2))
print(ob1.__add__(ob2))
Output
3 GeeksFor 3 3
Explanation:
- ob1 + ob2 automatically calls ob1.__add__(ob2).
- Python translates it into A.__add__(ob1, ob2).
- first operand (ob1) becomes self and second operand (ob2) becomes other.
Example 2: This code shows how to overload + operator for a custom Complex class so that it adds real and imaginary parts separately.
class Complex:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
return self.a + other.a, self.b + other.b
Ob1 = Complex(1, 2)
Ob2 = Complex(2, 3)
Ob3 = Ob1 + Ob2
print(Ob3)
Output
(3, 5)
Explanation: Here, Ob1 + Ob2 adds the real parts (1+2) and imaginary parts (2+3) separately.
Overloading Comparison Operators
Operators like >, <, and == can also be overloaded.
Example 1: This code shows how to overload > operator to compare two objects based on their stored values.
class A:
def __init__(self, a):
self.a = a
def __gt__(self, other):
return self.a > other.a
ob1 = A(2)
ob2 = A(3)
if ob1 > ob2:
print("ob1 is greater than ob2")
else:
print("ob2 is greater than ob1")
Output
ob2 is greater than ob1
Example 2: This code shows how to overload both < and == operators for custom comparisons.
class A:
def __init__(self, a):
self.a = a
def __lt__(self, other):
return "ob1 is less than ob2" if self.a < other.a else "ob2 is less than ob1"
def __eq__(self, other):
return "Both are equal" if self.a == other.a else "Not equal"
ob1 = A(2)
ob2 = A(3)
print(ob1 < ob2)
ob3 = A(4)
ob4 = A(4)
print(ob3 == ob4)
Output
ob1 is less than ob2 Both are equal
Non-Associative Operators
Not all operators can be chained. Some are non-associative. For example, = and += cannot be combined in one statement.
a = 5
b = 10
c = 15
# Invalid: mixing assignment (=) and +=
# a = b = (a < b) += (b < c)
Explanation: In Python, = (assignment) and += (augmented assignment) cannot be mixed in same expression because they are non-associative.
Overloading Boolean Operators
We can also overload Boolean operators using magic methods:
- and: __and__(self, other)
- or: __or__(self, other)
- not: __not__(self)
Example: This code shows how to overload & operator so it works like logical AND on custom objects.
class MyClass:
def __init__(self, value):
self.value = value
def __and__(self, other):
return MyClass(self.value and other.value)
a = MyClass(True)
b = MyClass(False)
c = a & b
print(c.value)
Output
False
Explanation: Here, we redefined & so it works like logical AND for custom objects.
Special (Magic) Methods for Operator Overloading
Python provides specific magic methods for each operator.
Binary Operators
| Operator | Magic Method |
|---|---|
| + | __add__(self, other) |
| - | __sub__(self, other) |
| * | __mul__(self, other) |
| / | __truediv__(self, other) |
| // | __floordiv__(self, other) |
| % | __mod__(self, other) |
| ** | __pow__(self, other) |
Comparison Operators
| Operator | Magic Method |
|---|---|
| < | __lt__(self, other) |
| > | __gt__(self, other) |
| <= | __le__(self, other) |
| >= | __ge__(self, other) |
| == | __eq__(self, other) |
| != | __ne__(self, other) |
Assignment Operators
| Operator | Magic Method |
|---|---|
| -= | __isub__(self, other) |
| += | __iadd__(self, other) |
| *= | __imul__(self, other) |
| /= | __itruediv__(self, other) |
| //= | __ifloordiv__(self, other) |
| %= | __imod__(self, other) |
| **= | __ipow__(self, other) |
Unary Operators
| Operator | Magic Method |
|---|---|
| - | __neg__(self) |
| + | __pos__(self) |
| ~ | __invert__(self) |
Advantages
Overloading operators in custom classes provides several benefits:
- Improved readability: code looks natural (e.g., ob1 + ob2 instead of ob1.add(ob2)).
- Consistency with built-in types: custom objects behave like integers, strings, etc.
- Conciseness: less boilerplate code.
- Custom behavior: extend operators to user-defined classes (e.g., vectors, matrices).
- Enhanced functionality: enable operators to work meaningfully with new data types.