Dunder Methods
What are dunder methods?
Section titled “What are dunder methods?”Dunder methods (short for double-underscore) are special methods like __repr__, __eq__, and __add__ that Python calls automatically in response to built-in syntax and functions.
They are the mechanism behind the Python Data Model — the contract that lets your objects behave like built-in types.
__repr__ and __str__
Section titled “__repr__ and __str__”Both produce string representations, but they serve different audiences:
| Method | When called | Purpose |
|---|---|---|
__repr__ | repr(obj), interactive shell | Unambiguous developer representation |
__str__ | str(obj), print(obj) | Human-friendly display |
If only __repr__ is defined, Python uses it for both.
The convention for __repr__ is to return a string that, if passed to eval(), would recreate the object.
class Point: def __init__(self, x: float, y: float) -> None: self.x = x self.y = y
def __repr__(self) -> str: return f"Point({self.x}, {self.y})"
def __str__(self) -> str: return f"({self.x}, {self.y})"__eq__ — equality
Section titled “__eq__ — equality”Python calls __eq__ when you write a == b.
Without it, == falls back to identity comparison (is) — two separate instances with the same data are never equal.
def __eq__(self, other: object) -> bool: if not isinstance(other, Point): return NotImplemented return self.x == other.x and self.y == other.yReturn NotImplemented (not False) when the types are incompatible — this lets Python try the reflected operation on the other operand.
__len__ and __getitem__
Section titled “__len__ and __getitem__”Implement __len__ to support len(obj).
Implement __getitem__ to support obj[index] subscript access.
Together they also make the object iterable via a for loop (Python calls __getitem__ with 0, 1, 2, … until IndexError).
def __len__(self) -> int: return 2
def __getitem__(self, index: int) -> float: return (self.x, self.y)[index]Operator overloading with __add__
Section titled “Operator overloading with __add__”Arithmetic operators map to dunder methods:
| Operator | Method |
|---|---|
a + b | a.__add__(b) |
a - b | a.__sub__(b) |
a * b | a.__mul__(b) |
a == b | a.__eq__(b) |
a < b | a.__lt__(b) |
def __add__(self, other: "Vector") -> "Vector": return Vector(self.x + other.x, self.y + other.y)Full runnable demo
Section titled “Full runnable demo”class Vector: def __init__(self, x: float, y: float) -> None: self.x = x self.y = y
def __repr__(self) -> str: return f"Vector({self.x}, {self.y})"
def __str__(self) -> str: return f"({self.x}, {self.y})"
def __eq__(self, other: object) -> bool: if not isinstance(other, Vector): return NotImplemented return self.x == other.x and self.y == other.y
def __add__(self, other: "Vector") -> "Vector": return Vector(self.x + other.x, self.y + other.y)
def __len__(self) -> int: return 2
def __getitem__(self, index: int) -> float: return (self.x, self.y)[index]
v1 = Vector(1, 2)v2 = Vector(3, 4)print(repr(v1))print(str(v1))print(v1 == Vector(1, 2))print(v1 + v2)print(len(v1))print(v1[0], v1[1])Loading Python runtime (first run only)…