What are dunder (magic) methods, and how do they enable operator overloading?

6 minintermediatefundamentalsdunder-methodsoperator-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

SyntaxDunder 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.