CodeOath
← All posts
Python70 min total · 18 parts

Python Fundamentals for Interviews: Data Structures, Comprehensions, and Gotchas

Contents — Part 14 of 18: Dunder Methods and Operator Overloading
Part 14 of 18 · ~1 min

Dunder Methods and Operator Overloading

"Dunder" (double underscore) methods are how Python objects hook into built-in syntax and functions — __init__ for construction is the one everyone knows, but many operators and built-ins are dunder methods underneath:

class Vector:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"   # unambiguous, dev-facing representation

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __len__(self):
        return int((self.x ** 2 + self.y ** 2) ** 0.5)

v1, v2 = Vector(1, 2), Vector(3, 4)
v1 + v2      # Vector(4, 6) — calls v1.__add__(v2)
v1 == Vector(1, 2)  # True — calls v1.__eq__
print(v1)    # Vector(1, 2) — calls __repr__ since __str__ isn't defined
len(v1)      # 2 — calls __len__
SyntaxDunder method called
obj + other__add__
obj == other__eq__
obj[key]__getitem__
len(obj)__len__
str(obj) / print(obj)__str__ (falls back to __repr__)
for x in obj__iter__
with obj:__enter__ / __exit__

__repr__ vs. __str__

__repr__ should be an unambiguous, ideally-eval-able representation aimed at developers (used by the console/debugger and as the fallback for print() when __str__ isn't defined); __str__ is a human-readable representation aimed at end users. Defining __repr__ alone covers both cases reasonably; defining only __str__ leaves debugging output (in a list, in a debugger, in a traceback) showing the unhelpful default <Vector object at 0x...>.