Python Dunder Methods — Making Custom Classes Pythonic
The Interview Question
What are dunder methods in Python? Which ones are most important to implement?
Expert Answer
Dunder (double underscore) methods are special methods that Python calls implicitly when you use built-in operations on objects. They're what makes Python's operator overloading and protocol system work. When you write len(obj), Python calls obj.__len__(). When you write obj1 + obj2, it calls obj1.__add__(obj2). When you print(obj), it calls obj.__repr__() or obj.__str__(). The most important ones to know: __init__ (constructor), __repr__ (developer-facing string — should be unambiguous), __str__ (user-facing string — should be readable), __eq__ and __hash__ (equality and hashing — if you override __eq__, you must also handle __hash__), __len__ (length), __iter__ and __next__ (make objects iterable), __getitem__ (bracket access like obj[key]), and __enter__/__exit__ (context manager protocol). The principle: implement dunders to make your classes feel like native Python types, not to be clever.
Key Points to Hit in Your Answer
- __repr__ should return a string that could recreate the object; __str__ is for display
- If you define __eq__, Python sets __hash__ to None — define both or neither
- __iter__ + __next__ make objects work in for loops, list(), etc.
- __getitem__ enables bracket access and slicing
- __call__ makes instances callable like functions
- dataclasses auto-generate __init__, __repr__, __eq__ — use them for simple data holders
Code Example
class Money:
def __init__(self, amount, currency="USD"):
self.amount = amount
self.currency = currency
def __repr__(self):
return f"Money({self.amount}, '{self.currency}')"
def __str__(self):
return f"${self.amount:.2f} {self.currency}"
def __eq__(self, other):
return self.amount == other.amount and self.currency == other.currency
def __hash__(self):
return hash((self.amount, self.currency))
def __add__(self, other):
if self.currency != other.currency:
raise ValueError("Cannot add different currencies")
return Money(self.amount + other.amount, self.currency)
def __lt__(self, other):
return self.amount < other.amount
m1 = Money(10)
m2 = Money(20)
print(m1 + m2) # $30.00 USD (__add__ + __str__)
print(repr(m1)) # Money(10, 'USD') (__repr__)
sorted([m2, m1]) # [Money(10, 'USD'), Money(20, 'USD')] (__lt__)
{m1: "ten"} # works as dict key (__hash__ + __eq__)
What Interviewers Are Really Looking For
The __repr__ vs __str__ distinction is a common question. __repr__ is for developers (unambiguous), __str__ is for users (readable). The __eq__/__hash__ relationship is critical — if two objects are equal, they must have the same hash. Mentioning dataclasses as the modern shortcut for data-holding classes shows practical awareness.
Practice This Question with AI Grading
Reading about interview questions is a start — but practicing with real-time AI feedback is how you actually get better. Goliath Prep grades your answers instantly and tells you exactly what you're missing.
Start Practicing Free →