Python Dunder (Magic) Methods


What Are Dunder Methods in Python?

Dunder methods (short for "Double UNDERscore" methods) are special methods in Python that begin and end with double underscores, like __init__, __str__, __len__, etc. These are also called magic methods because Python internally uses them to enable built-in behavior such as initialization, operator overloading, string representation, comparisons, and more.

Why Use Dunder Methods?

  • To customize class behavior
  • To make objects behave like built-in types
  • To implement operator overloading
  • To support built-in functions like len(), str(), int(), etc.

Most Commonly Used Dunder Methods

Dunder Method Purpose
__init__ Object initialization (constructor)
__str__ Human-readable string representation
__repr__ Developer-readable representation
__len__ Length using len()
__add__ Addition with +
__eq__ Equality with ==
__lt__ Less than with <
__getitem__ Indexing with []
__call__ Make instance callable like a function


Example 1: __init__, __str__, and __repr__

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}')"

book = Book("1984", "George Orwell")
print(str(book))
print(repr(book))

Output:

1984 by George Orwell
Book('1984', 'George Orwell')


Example 2: __len__ and __getitem__

class Playlist:
    def __init__(self, songs):
        self.songs = songs

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

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

pl = Playlist(["Song A", "Song B", "Song C"])
print(len(pl))
print(pl[1])

Output:

3
Song B


Example 3: __add__ and __eq__ (Operator Overloading)

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

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

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

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

m1 = Money(50)
m2 = Money(70)
m3 = m1 + m2

print(m3)          # $120
print(m1 == m2)    # False

Output:

$120
False


Example 4: __call__ - Making Objects Callable

class Greeter:
    def __init__(self, name):
        self.name = name

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

greet = Greeter("Alice")
print(greet())  # Object behaves like a function

Output:

Hello, Alice!

Best Practices for Using Dunder Methods

  • Use __str__ for user-friendly output and __repr__ for debugging
  • Overload operators only when it makes logical sense
  • Avoid overusing magic methods—only implement what's needed
  • Keep behavior consistent with Python's built-in types