Python Magic Methods

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.

MethodPurpose
__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

3

That 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

True
False

Without __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

10
20
30

That 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

10
15

That 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 + cart2
print(combined)
print(f"Items in combined: {len(combined)}")

Output

Apple: $1.5
Banana: $0.75
Items in cart1: 2
Apple: $1.5
Banana: $0.75
Orange: $2.0
Items in combined: 3

That 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.

MethodPurpose
__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 returning

This 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.x

This works, but it is confusing. The parameter should be other.

Fix:

def __eq__(self, other):
return self.x == other.x

Mistake 3: Forgetting that magic methods are called automatically

person = Person("Alex", 25)
person.__str__() # Works, but not the right way

Fix: 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.x

If 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.y

Next, we will learn about Python Modules and organize reusable code in separate files.