What are dunder (magic) methods, and how do they enable operator overloading?
Quick Answer
Dunder methods (`__init__`, `__add__`, `__eq__`, `__len__`, `__getitem__`, etc.) are hooks that Python's syntax and built-in functions call implicitly — `a + b` calls `a.__add__(b)`, `len(x)` calls `x.__len__()`, `x[i]` calls `x.__getitem__(i)`. Implementing them lets user-defined classes participate in built-in syntax (arithmetic, comparisons, iteration, indexing, context managers) the same way built-in types do.
Detailed Answer
How operator syntax maps to method calls
class Money:
def __init__(self, cents):
self.cents = cents
def __add__(self, other):
return Money(self.cents + other.cents)
def __eq__(self, other):
return self.cents == other.cents
def __repr__(self):
return f"Money({self.cents})"
a = Money(150)
b = Money(50)
a + b # calls a.__add__(b) -> Money(200)
a == b # calls a.__eq__(b) -> False
a + b is syntax sugar that the interpreter desugars to
type(a).__add__(a, b) (falling back to type(b).__radd__(b, a) if a
doesn't know how to add b). Every piece of "special" syntax in Python has
a dunder method behind it.
Common categories
| Syntax | Dunder method(s) |
|---|---|
a + b, a - b, a * b | __add__, __sub__, __mul__ (+ __radd__, etc.) |
a == b, a < b | __eq__, __lt__, ... |
len(x) | __len__ |
x[i], x[i] = v | __getitem__, __setitem__ |
for i in x | __iter__ / __next__ |
with x: | __enter__, __exit__ |
str(x), repr(x) | __str__, __repr__ |
x() | __call__ |
hash(x) | __hash__ |
x in y | __contains__ |
The __eq__/__hash__ contract
If you override __eq__, Python sets __hash__ to None unless you
also define it, making instances unhashable (can't be used as dict keys
or set members). Two objects that are equal must have the same hash, so
if you define __eq__, define a consistent __hash__ too (or explicitly
leave the class unhashable if that's intended).
Why this is more than syntax sugar
Dunders are how Python achieves polymorphism without a common base class
requirement — any object implementing __iter__/__next__ works in a
for loop, any object implementing __enter__/__exit__ works in a
with block. It's the mechanism duck typing runs on.
Interview-ready summary: Dunder methods are the hooks that back
Python's operators and built-in functions — +, ==, len(), indexing,
iteration, and context managers all desugar to method calls on the
operand's type. Implementing them lets custom classes plug into the same
syntax built-in types use, and overriding __eq__ without __hash__ makes
instances unhashable.