Python Magic Methods
Table of Contents
In the last lesson, we learned about Python Abstraction. After learning about abstraction, let us learn about magic methods in Python. Magic methods are special methods that have double underscores before and after their names. They are also called dunder methods.
In this tutorial, we will learn what magic methods are, how to use them, and why they are useful.
What Are Magic Methods in Python?
Magic methods are special methods that Python calls automatically in certain situations. They let us define how our objects behave with built-in operations.
For example, when we add two numbers, Python calls the __add__ method. When we print an object, Python calls the __str__ method.
We do not call these methods directly. Python calls them for us.
Common Magic Methods in Python
Here are some of the most common magic methods.
| Method | Purpose |
|---|---|
__init__ | Constructor |
__str__ | String representation for users |
__repr__ | String representation for developers |
__len__ | Length of the object |
__add__ | Addition |
__eq__ | Equality comparison |
__lt__ | Less than comparison |
__getitem__ | Indexing |
__call__ | Calling the object like a function |
Let me show you some of them.
The str and repr Methods in Python
The __str__ method returns a string that is easy to read. It is used by print() and str().
The __repr__ method returns a string that is useful for debugging. It is used by repr().
class Person: def __init__(self, name, age): self.name = name self.age = age
def __str__(self): return f"{self.name} ({self.age})"
def __repr__(self): return f"Person('{self.name}', {self.age})"
person = Person("Alex", 25)
print(str(person))print(repr(person))Output
Alex (25)Person('Alex', 25)The __str__ is for users. The __repr__ is for developers.
The len Method in Python
The __len__ method lets us use len() on our objects.
class Playlist: def __init__(self, songs): self.songs = songs
def __len__(self): return len(self.songs)
playlist = Playlist(["Song 1", "Song 2", "Song 3"])print(len(playlist))Output
3That is clean and intuitive.
The add Method in Python
The __add__ method lets us use + on our objects.
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})"
v1 = Vector(1, 2)v2 = Vector(3, 4)v3 = v1 + v2
print(v3)Output
Vector(4, 6)That is how we can make our objects support addition.
The eq Method in Python
The __eq__ method lets us use == on our objects.
class Point: def __init__(self, x, y): self.x = x self.y = y
def __eq__(self, other): return self.x == other.x and self.y == other.y
p1 = Point(1, 2)p2 = Point(1, 2)p3 = Point(3, 4)
print(p1 == p2)print(p1 == p3)Output
TrueFalseWithout __eq__, Python would compare object identity, not values. So p1 == p2 would be False.
The getitem Method in Python
The __getitem__ method lets us use indexing on our objects.
class MyList: def __init__(self, items): self.items = items
def __getitem__(self, index): return self.items[index]
my_list = MyList([10, 20, 30])
print(my_list[0])print(my_list[1])print(my_list[2])Output
102030That makes our object behave like a list.
The call Method in Python
The __call__ method lets us call our objects like functions.
class Multiplier: def __init__(self, factor): self.factor = factor
def __call__(self, x): return x * self.factor
double = Multiplier(2)triple = Multiplier(3)
print(double(5))print(triple(5))Output
1015That is a neat trick. It makes our objects callable.
A Real-Life Example β Shopping Cart
Letβs create a shopping cart class with magic methods.
class ShoppingCart: def __init__(self): self.items = []
def add(self, item, price): self.items.append((item, price))
def __len__(self): return len(self.items)
def __str__(self): if not self.items: return "Empty cart" lines = [f"{item}: ${price}" for item, price in self.items] return "\n".join(lines)
def __add__(self, other): new_cart = ShoppingCart() new_cart.items = self.items + other.items return new_cart
cart1 = ShoppingCart()cart1.add("Apple", 1.50)cart1.add("Banana", 0.75)
cart2 = ShoppingCart()cart2.add("Orange", 2.00)
print(cart1)print(f"Items in cart1: {len(cart1)}")
combined = cart1 + cart2print(combined)print(f"Items in combined: {len(combined)}")Output
Apple: $1.5Banana: $0.75Items in cart1: 2Apple: $1.5Banana: $0.75Orange: $2.0Items in combined: 3That shows how magic methods make our objects behave like built-in types.
Common Magic Methods to Know in Python
Here are some more magic methods worth knowing.
| Method | Purpose |
|---|---|
__sub__ | Subtraction |
__mul__ | Multiplication |
__truediv__ | Division |
__mod__ | Modulo |
__pow__ | Power |
__ne__ | Not equal |
__gt__ | Greater than |
__ge__ | Greater than or equal |
__le__ | Less than or equal |
__contains__ | in operator |
__iter__ | Iteration |
__next__ | Next item in iteration |
__enter__ | Context manager enter |
__exit__ | Context manager exit |
We do not need to memorize all of them. Just know they exist. And use them when needed.
Common Mistakes with Magic Methods in Python
Mistake 1: Forgetting to return a value
class Point: def __init__(self, x, y): self.x = x self.y = y
def __str__(self): print(f"Point({self.x}, {self.y})") # prints instead of returningThis gives an error when we use str() or print(). Because __str__ must return a string.
Fix:
def __str__(self): return f"Point({self.x}, {self.y})"Mistake 2: Using the wrong parameter name
class Point: def __eq__(self, x): return self.x == x.xThis works, but it is confusing. The parameter should be other.
Fix:
def __eq__(self, other): return self.x == other.xMistake 3: Forgetting that magic methods are called automatically
person = Person("Alex", 25)person.__str__() # Works, but not the right wayFix: Use the built-in functions.
print(person)str(person)Mistake 4: Not handling the case when other is not the same type
class Point: def __eq__(self, other): return self.x == other.xIf other is not a Point, this gives an error.
Fix:
def __eq__(self, other): if not isinstance(other, Point): return False return self.x == other.x and self.y == other.yNext, we will learn about Python Modules and organize reusable code in separate files.