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