Did you ever wonder why the + operator adds two numbers (10 + 20 -> 30) but concatenates two strings ("Hello" + "World")? That is Operator Overloading in action. By implementing special dunder (double underscore) magic methods in your custom classes, you can define how standard operators behave with your own objects.
class Vector2D:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
# Overload '+' operator:
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)
# Overload '-' operator:
def __sub__(self, other):
return Vector2D(self.x - other.x, self.y - other.y)
# Overload '==' operator:
def __eq__(self, other):
return self.x == other.x and self.y == other.y
# User-friendly string representation for print():
def __str__(self):
return f"Vector({self.x}, {self.y})"
# Developer debugging representation:
def __repr__(self):
return f"Vector2D(x={self.x}, y={self.y})"
v1 = Vector2D(2, 4)
v2 = Vector2D(5, 1)
# Using overloaded '+' operator:
v3 = v1 + v2
print("Result of v1 + v2:", v3) # Vector(7, 5)
print("Are v1 and v2 equal?:", v1 == v2) # False
| Operator | Magic Dunder Method | Triggered When |
|---|---|---|
+ | __add__(self, other) | a + b |
- | __sub__(self, other) | a - b |
* | __mul__(self, other) | a * b |
/ | __truediv__(self, other) | a / b |
== | __eq__(self, other) | a == b |
< | __lt__(self, other) | a < b |
len() | __len__(self) | len(a) |
a[key] | __getitem__(self, key) | Indexing subscript access |
+, -, *, ==, <). You cannot invent arbitrary new symbols like @@ or %%=.