This is achieved through special built-in methods known as magic methods or dunder methods (because they start and end with double underscores, like add or str).
Why Operator Overloading?
By default, Python's operators are defined for built-in data types. For example, the + operator adds numbers or concatenates strings, but it doesn't know how to handle custom objects.With operator overloading, you can define what + or any other operator should do when used with objects of your own class.
Example without overloading:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p1 = Point(2, 3)
p2 = Point(4, 5)
print(p1 + p2) # Error
Output:
TypeError: unsupported operand type(s) for +: 'Point' and 'Point'
To make this work, we need to overload the + operator using the add() method.
Using Magic Methods
Python provides a set of special methods that you can define inside your class to override built-in operators’ behavior.Example:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
if isinstance(other, Point):
return Point(self.x + other.x, self.y + other.y)
return NotImplemented
def __str__(self):
return f"({self.x}, {self.y})"
p1 = Point(2, 3)
p2 = Point(4, 5)
print(p1 + p2)
Output:
(6, 8)
Here:
add() defines how the + operator behaves.
str() defines how the object should be represented as a string when printed.
Commonly Used Magic Methods in Python
| Operator | Magic Method | Description |
|---|---|---|
| + | __add__(self, other) | Adds two objects |
| - | __sub__(self, other) | Subtracts one object from another |
| * | __mul__(self, other) | Multiplies two objects |
| / | __truediv__(self, other) | Divides two objects |
| // | __floordiv__(self, other) | Performs floor division |
| == | __eq__(self, other) | Checks equality of two objects |
| != | __ne__(self, other) | Checks inequality |
| > | __gt__(self, other) | Greater than comparison |
| < | __lt__(self, other) | Less than comparison |
| str(obj) | __str__(self) | String representation of an object |
| len(obj) | __len__(self) | Returns length of an object |
| in | __contains__(self, item) | Membership test |
Example: Comparison Operators
You can also overload comparison operators like == or > to compare custom objects meaningfully.class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
def __gt__(self, other):
return self.marks > other.marks
def __eq__(self, other):
return self.marks == other.marks
s1 = Student("Alice", 85)
s2 = Student("Bob", 90)
s3 = Student("Carol", 85)
print(s1 > s2) # False
print(s1 == s3) # True
Output:
False
True
Here, the operators > and == now compare marks instead of memory addresses.
Overloading __str__() and __repr__()
str() and repr() control how objects are displayed when printed or inspected in the console.class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def __str__(self):
return f"{self.title} by {self.author}"
def __repr__(self):
return f"Book('{self.title}', '{self.author}')"
b = Book("1984", "George Orwell")
print(b)
print(str(b))
print(repr(b))
Output:
1984 by George Orwell
1984 by George Orwell
Book('1984', 'George Orwell')
str() → user-friendly output (for print()). It is called by the print() function, the str() built-in function, and string formatting operations.
repr() → developer-friendly representation (used in the console or debugging). It is called by the repr() built-in function, when an object is evaluated in the interactive interpreter (REPL), and in debugging tools.
Example – Subtraction and Multiplication:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(4, 5)
v2 = Vector(2, 3)
print(v1 - v2)
print(v1 * 3)
Output:
Vector(2, 2)
Vector(12, 15)
Summary
Operator overloading makes your Python classes more intuitive and expressive. By implementing magic methods, you can seamlessly integrate your custom objects with Python’s built-in operations — improving code readability and flexibility.| Concept | Description |
|---|---|
| Operator Overloading | Redefining built-in operators for custom objects |
| Magic Methods | Special methods (like __add__, __str__) that define operator behavior |
| __add__() | Defines how the + operator works |
| __str__() | Defines the object’s printable (user-friendly) representation |
| __eq__(), __gt__() | Enable custom equality and comparison operations |
| __repr__() | Returns a developer-friendly representation of the object |