Python OOPs: 0 to Infinity

Magic Methods in Python OOP

Learn how special double-underscore methods such as __init__, __str__, __len__, __add__, and __getitem__ allow your own classes to behave like natural Python objects.

Beginner friendly Operator overloading Real examples Practice project

1. What are magic methods?

In Python Object-Oriented Programming, magic methods are special methods whose names start and end with double underscores. They are also called dunder methods.

__init__
__str__
__repr__
__len__
__add__
__getitem__

We usually do not call these methods directly. Python calls them automatically when we perform normal actions.

Normal action Magic method Python calls
print(obj) obj.__str__()
len(obj) obj.__len__()
obj1 + obj2 obj1.__add__(obj2)
obj[index] obj.__getitem__(index)
Simple idea: Magic methods teach Python how your own objects should behave when used with ordinary Python syntax.

2. __init__: the object setup method

The __init__ method runs automatically when a new object is created. It is used to store the first values inside an object.

class Student:
    def __init__(self, name, marks):
        self.name = name
        self.marks = marks


s1 = Student("Amit", 85)

print(s1.name)
print(s1.marks)

Output:

Amit
85
Checkpoint: When we write Student("Amit", 85), Python automatically calls __init__.

Common beginner confusion

__init__ is not the object itself. It is the method that prepares the object after it is created.

3. __str__ and __repr__: showing objects properly

Without __str__

class Student:
    def __init__(self, name, marks):
        self.name = name
        self.marks = marks


s1 = Student("Amit", 85)
print(s1)

Output may look like this:

<__main__.Student object at 0x000001A2...>

This output is not useful for a student or a normal user.

With __str__

class Student:
    def __init__(self, name, marks):
        self.name = name
        self.marks = marks

    def __str__(self):
        return f"{self.name} scored {self.marks} marks"


s1 = Student("Amit", 85)
print(s1)

Output:

Amit scored 85 marks

Using __repr__

__repr__ is generally used for programmer-friendly output.

class Student:
    def __init__(self, name, marks):
        self.name = name
        self.marks = marks

    def __repr__(self):
        return f"Student(name='{self.name}', marks={self.marks})"


s1 = Student("Amit", 85)
print(repr(s1))

Output:

Student(name='Amit', marks=85)
Method Purpose
__str__ Friendly output for users
__repr__ Clear output for programmers and debugging

4. Operator overloading with magic methods

Operator overloading means giving special meaning to operators such as +, -, *, and > for our own classes.

Problem first

class Money:
    def __init__(self, amount):
        self.amount = amount


m1 = Money(100)
m2 = Money(200)

print(m1 + m2)

Python does not automatically know how to add two Money objects. So we define __add__.

Solution with __add__

class Money:
    def __init__(self, amount):
        self.amount = amount

    def __add__(self, other):
        return Money(self.amount + other.amount)

    def __str__(self):
        return f"₹{self.amount}"


m1 = Money(100)
m2 = Money(250)

m3 = m1 + m2

print(m3)

Output:

₹350
Checkpoint: When we write m1 + m2, Python internally calls m1.__add__(m2).

Common operator magic methods

Operator Magic method
+__add__
-__sub__
*__mul__
/__truediv__
//__floordiv__
%__mod__
**__pow__

Example with boxes

class Box:
    def __init__(self, chocolates):
        self.chocolates = chocolates

    def __add__(self, other):
        return Box(self.chocolates + other.chocolates)

    def __sub__(self, other):
        return Box(self.chocolates - other.chocolates)

    def __str__(self):
        return f"Box has {self.chocolates} chocolates"


b1 = Box(20)
b2 = Box(5)

print(b1 + b2)
print(b1 - b2)

Output:

Box has 25 chocolates
Box has 15 chocolates

5. Comparison magic methods

Comparison magic methods allow us to compare two objects using normal comparison operators.

Comparison Magic method
==__eq__
!=__ne__
>__gt__
<__lt__
>=__ge__
<=__le__

Student marks comparison

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("Amit", 85)
s2 = Student("Ravi", 90)
s3 = Student("Sita", 85)

print(s1 > s2)
print(s1 == s3)

Output:

False
True
We compared students by marks, but we could also compare them by age, rank, fees, attendance, or any other data.

6. Making objects behave like containers

Python lists, tuples, dictionaries, and strings support operations such as len(), indexing, assignment by index, and in. Magic methods allow our own objects to support these actions too.

__len__: support for len()

class Classroom:
    def __init__(self, students):
        self.students = students

    def __len__(self):
        return len(self.students)


c1 = Classroom(["Amit", "Ravi", "Sita"])

print(len(c1))

Output:

3

__getitem__: support for indexing

class Marksheet:
    def __init__(self, marks):
        self.marks = marks

    def __getitem__(self, index):
        return self.marks[index]


m = Marksheet([80, 75, 90, 88])

print(m[0])
print(m[2])

Output:

80
90

__setitem__: support for changing values by index

class Marksheet:
    def __init__(self, marks):
        self.marks = marks

    def __getitem__(self, index):
        return self.marks[index]

    def __setitem__(self, index, value):
        self.marks[index] = value


m = Marksheet([80, 75, 90])

print(m[1])
m[1] = 95
print(m[1])

Output:

75
95

__contains__: support for in

class Classroom:
    def __init__(self, students):
        self.students = students

    def __contains__(self, name):
        return name in self.students


c = Classroom(["Amit", "Ravi", "Sita"])

print("Amit" in c)
print("Mohan" in c)

Output:

True
False

7. Advanced but useful magic methods

__call__

This method makes an object behave like a function.

class Greeter:
    def __call__(self, name):
        return f"Hello, {name}!"


g = Greeter()

print(g("Amit"))
print(g("Sita"))

Output:

Hello, Amit!
Hello, Sita!

__bool__

This method controls truth testing with if object:.

class Wallet:
    def __init__(self, money):
        self.money = money

    def __bool__(self):
        return self.money > 0


w1 = Wallet(500)
w2 = Wallet(0)

print(bool(w1))
print(bool(w2))

Output:

True
False

__del__: object destruction

The method __del__ may run when an object is about to be destroyed. However, in real projects we should not depend on its exact timing.

class Demo:
    def __init__(self):
        print("Object created")

    def __del__(self):
        print("Object destroyed")


d = Demo()
del d
Important: Do not use __del__ as your main cleanup plan in serious programs. Python controls memory automatically, and destruction time may not always be exactly when you expect.

8. Mini project: Shopping Cart with magic methods

This project shows how magic methods make our own class feel natural, like a normal Python container.

class ShoppingCart:
    def __init__(self):
        self.items = []

    def add_item(self, item):
        self.items.append(item)

    def __len__(self):
        return len(self.items)

    def __contains__(self, item):
        return item in self.items

    def __getitem__(self, index):
        return self.items[index]

    def __str__(self):
        return f"Cart contains: {self.items}"


cart = ShoppingCart()

cart.add_item("Laptop")
cart.add_item("Mouse")
cart.add_item("Keyboard")

print(cart)
print(len(cart))
print("Mouse" in cart)
print(cart[0])

Output:

Cart contains: ['Laptop', 'Mouse', 'Keyboard']
3
True
Laptop
Checkpoint: This object supports print(cart), len(cart), "Mouse" in cart, and cart[0].

9. Practice questions

Question 1: Book class

Create a class called Book. It should have title and pages. Use __str__ to print this:

Python Basics has 250 pages
Question 2: Box class

Create a class called Box. It should store items. Use __len__ so that len(box) works.

Question 3: Product class

Create a class called Product. It should have name and price. Use __gt__ to compare products by price.

Question 4: Wallet class

Create a class called Wallet. It should have money. Use __add__ to add two wallets.

w1 = Wallet(100)
w2 = Wallet(200)

print(w1 + w2)

Expected output:

300
Question 5: Marksheet class

Create a class called Marksheet that stores a list of marks. Add __len__, __getitem__, and __setitem__.

10. Practice in the Python editor

Use the embedded editor below to run the examples. Start by copying the ShoppingCart project, then modify it.

11. Final summary

Magic methods are special double-underscore methods that allow your objects to behave like Python’s built-in objects.

Action Method Python looks for
print(obj)__str__
repr(obj)__repr__
len(obj)__len__
obj1 + obj2__add__
obj1 > obj2__gt__
obj[index]__getitem__
obj[index] = value__setitem__
value in obj__contains__
obj()__call__
if obj:__bool__
Final line: Magic methods teach Python how your own objects should respond to normal Python actions.