Learning

Magic / Dunder Methods

Magic / Dunder Methods

str & repr

python
class Point: def __init__(self, x, y): self.x, self.y = x, y def __str__(self): return f'Point({self.x}, {self.y})' def __repr__(self): return f'Point(x={self.x}, y={self.y})' p = Point(3, 4) print(str(p)) # Point(3, 4) — for users print(repr(p)) # Point(x=3, y=4) — for developers print(p) # Point(3, 4) — print uses __str__

len & getitem

python
class Squares: def __init__(self, n): self.n = n def __len__(self): return self.n def __getitem__(self, index): if index < 0 or index >= self.n: raise IndexError('out of range') return index ** 2 sq = Squares(5) print(len(sq)) # 5 print(sq[0]) # 0 print(sq[3]) # 9 for s in sq: # Works because __getitem__ + __len__ = iterable! print(s, end=' ') # 0 1 4 9 16

add & eq

python
class Vector: def __init__(self, x, y): self.x, self.y = x, y def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) def __eq__(self, other): return self.x == other.x and self.y == other.y def __repr__(self): return f'Vector({self.x}, {self.y})' v1 = Vector(1, 2) v2 = Vector(3, 4) print(v1 + v2) # Vector(4, 6) print(v1 == v2) # False print(Vector(1,2) == Vector(1,2)) # True

call

python
class Multiplier: def __init__(self, factor): self.factor = factor def __call__(self, x): return x * self.factor double = Multiplier(2) triple = Multiplier(3) print(double(5)) # 10 print(triple(5)) # 15

iter & next

python
class Countdown: def __init__(self, start): self.current = start def __iter__(self): return self def __next__(self): if self.current <= 0: raise StopIteration self.current -= 1 return self.current + 1 for n in Countdown(3): print(n, end=' ') # 3 2 1

enter & exit

python
class Timer: def __enter__(self): import time self.start = time.time() return self def __exit__(self, *args): import time print(f'Elapsed: {time.time() - self.start:.4f}s') with Timer(): sum(range(1000000)) # Elapsed: 0.0312s
Key Rules
  • •__str__ is for end users (readable), __repr__ is for developers (unambiguous, ideally eval-able)
  • •__len__ + __getitem__ automatically makes your class iterable by for loops
  • •Arithmetic dunder methods (__add__, __sub__, etc.) should return NEW objects, not modify self
  • •__call__ makes instances behave like functions — useful for stateful callables
  • •__enter__ and __exit__ enable 'with' statement support for resource management
  • •Always return NotImplemented (not raise) from dunder methods when the operation isn't supported for the other type
Your Task

Create a `Fraction` class with `__init__(self, num, den)` that stores numerator and denominator. Implement `__str__` (as 'num/den'), `__repr__`, `__add__` (returns new Fraction with common denominator), `__eq__` (cross-multiply), `__lt__` (cross-multiply), and `__bool__` (False if num is 0). Demonstrate: `f1 = Fraction(1, 3)`, `f2 = Fraction(2, 6)`, print them, add them, compare them, check equality.

EditorPython · JSX
PreviewUpdates on Run Tests
Loading preview…
Tests
Should define Fraction class with num and den
Should implement __str__ returning num/den format
Should implement __add__ returning new Fraction
Should implement __eq__ with cross-multiplication
Should implement __lt__
Should implement __bool__ checking num != 0