Dunders (__add__, __eq__, __getitem__, …) plug a class into language protocols. Define them in the class body. The VM calls them when the matching operator, builtin, or syntax form runs.
7
TrueDunders are looked up on the class chain. The instance dict is skipped. Subclasses inherit and may override. Operator overloading composes with inheritance. Dispatch is cached per call site; see Design for the inline-cache mechanics.
Arithmetic
| Operator | Forward | Reflected |
|---|---|---|
a + b | __add__ | __radd__ |
a - b | __sub__ | __rsub__ |
a * b | __mul__ | __rmul__ |
a / b | __truediv__ | __rtruediv__ |
a // b | __floordiv__ | __rfloordiv__ |
a % b | __mod__ | __rmod__ |
a ** b | __pow__ | __rpow__ |
-a | __neg__ | - |
+a | __pos__ | - |
Return NotImplemented from the forward op to make the VM try the reflected op on the other operand. Both NotImplemented (or neither defined) -> TypeError.
Subclass-first: when type(b) is a strict subclass of type(a), b.__radd__ runs before a.__add__. This lets a subclass override an inherited reflected op without touching the base.
15
10Bitwise and shifts
The bitwise and shift operators follow the same forward/reflected protocol.
| Operator | Forward | Reflected |
|---|---|---|
a | b | __or__ | __ror__ |
a & b | __and__ | __rand__ |
a ^ b | __xor__ | __rxor__ |
a << b | __lshift__ | __rlshift__ |
a >> b | __rshift__ | __rrshift__ |
Comparison
| Operator | Forward | Reflected |
|---|---|---|
a == b | __eq__ | __eq__ |
a != b | __ne__ | __ne__ |
a < b | __lt__ | __gt__ |
a <= b | __le__ | __ge__ |
a > b | __gt__ | __lt__ |
a >= b | __ge__ | __le__ |
!= falls back to not __eq__ (coerced to bool) when __ne__ is absent. Every other comparison returns the dunder’s raw result: __lt__ returning 'A.lt' yields the string, not True.
Truth and length
bool(x) (and any boolean context) consults:
__bool__if defined (must returnbool, elseTypeError).__len__if defined ->Falsewhen length is 0, elseTrue.- Default
True.
len(x) calls __len__ directly. It must return a non-negative int.
False
False True
5Indexing and containment
| Form | Dunder | Arguments |
|---|---|---|
obj[i] | __getitem__ | (self, i) |
obj[i] = v | __setitem__ | (self, i, value) |
del obj[i] | __delitem__ | (self, i) |
v in obj | __contains__ | (self, value) |
Slices pass as a slice object: obj[1:3] calls __getitem__(self, slice(1, 3, None)).
Absent __contains__: v in obj falls back to iterating obj with __eq__.
Iteration
| Method | Role |
|---|---|
__iter__ | Returns an iterator (often self). |
__next__ | Returns the next item, or raises StopIteration to end the loop. |
[1, 2, 3]for loops, list(x), and tuple(x) all honour the protocol.
Callable
__call__ makes instances invocable. Positional and keyword arguments are forwarded like any method call.
14
21
TrueHashing
hash(x) calls __hash__. It must return int (masked to INT_MAX).
Eq/hash invariant: a class defining __eq__ without __hash__ is unhashable: hash(x) and {x: 1} raise TypeError. Prevents inconsistent dict keys.
5
foundBuilt-in dict/set compare instance keys by identity (Val bits). User __hash__ is returned by hash(), but doesn’t change containment in built-in containers. Use the same instance reference to look up reliably.
Representation
| Function / form | Dunder | Fallback |
|---|---|---|
repr(x) | __repr__ | <ClassName instance> |
str(x), print(x) | __str__ | __repr__, then default |
f"{x}" (no spec) | __str__ | same as str(x) |
f"{x:spec}" | __format__ | built-in format spec engine |
f"{x!r}" | __repr__ | - |
__format__(spec) receives the spec string and must return str. int(x) on an instance calls __int__, also used by %d / %x / %X / %o formatting.
Attribute access fallback
__getattr__(self, name) runs only when normal lookup (instance dict -> class chain) misses. It receives the name as a string. Return the value, or raise AttributeError to surface a real miss.
computed:anything
computed:fooExisting attributes bypass __getattr__. Only misses trigger it.
Context managers
with cm() as x: invokes __enter__. Its return binds to as. On exit, __exit__(exc_type, exc_value, traceback) runs: (None, None, None) for normal exit; on a raise, the exception type and value with traceback always None. A truthy return suppresses the exception; a falsy one propagates it.
afterMultiple managers (with a(), b() as x:) nest LIFO: b enters last, exits first. Each has its own implicit handler, so inner suppression still lets outer managers run their normal __exit__(None, None, None).
If __exit__ itself raises, the new exception replaces the original.
What’s not dispatched
Parsed for compatibility but never invoked on user classes:
__init_subclass__,__set_name__, descriptors (__get__/__set__/__delete__)__new__, VM constructs the instance;__init__runs user logic- Augmented-assignment dunders (
__iadd__, …),a += bdesugars toa = a + b, so__add__covers it. Exception: list+=extends in place (alias-visible); see Data types - Async dunders (
__aenter__/__aexit__/__aiter__/__anext__),async with/async foruse the sync paths
See also
- Classes: constructors, inheritance, properties.