CS 112 › Lesson 6 of 10

Dunder / Magic Methods

Lesson 6 · OKSTEM College · Associate of Science in Computer Science

What Are Dunder Methods?

Dunder (double-underscore) methods let your objects hook into Python's built-in operators and functions. Instead of calling obj.add(other), you write obj + other — Python calls obj.__add__(other) automatically.

DunderTriggered byCommon use
__str__str(obj), print(obj)Human-readable string
__repr__repr(obj), REPL displayDebug/unambiguous string
__len__len(obj)Return count of items
__add__obj + otherAddition / concatenation
__eq__obj == otherEquality comparison
__lt__obj < otherLess-than comparison
__iter__for x in objMake object iterable
__getitem__obj[key]Subscript access
__contains__x in objMembership test

Building a Vector Class

class Vector: def __init__(self, x, y): self.x = x; self.y = y def __repr__(self): return f"Vector({self.x}, {self.y})" def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) def __mul__(self, scalar): return Vector(self.x * scalar, self.y * scalar) def __abs__(self): return (self.x**2 + self.y**2) ** 0.5 def __eq__(self, other): return self.x == other.x and self.y == other.y v1 = Vector(1, 2) v2 = Vector(3, 4) print(v1 + v2) # Vector(4, 6) print(v1 * 3) # Vector(3, 6) print(abs(v2)) # 5.0 print(v1 == Vector(1,2)) # True

Making Objects Iterable

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

Practice Problems

1. Add __len__ to Vector that returns the number of components (2).

def __len__(self): return 2 # a 2D vector always has 2 components

2. When should you implement __repr__ vs __str__?

__repr__: unambiguous, developer-facing (shown in REPL, repr()). Should ideally be eval-able: repr(obj) gives you code to recreate it. __str__: readable, user-facing (shown by print(), str()). If only one is defined, Python falls back to __repr__ for both.

Knowledge Check

Dunder methods are called

You can, but that's not the point — Python calls them implicitly.
Correct — writing obj + x triggers __add__ automatically.
They're called from anywhere, including outside the class.
Dunder methods work on any class.
Recap: obj + other → Python calls obj.__add__(other). You write the dunder; Python wires it to the operator.

print(obj) calls which dunder?

print() prefers __str__; it falls back to __repr__ if __str__ is missing.
Correct — print() and str() call __str__ first.
No such dunder exists.
No such dunder exists.
Recap: str(obj) / print(obj)__str__. repr(obj)__repr__. Define both when possible.

To make for x in obj work, your class needs

These dunders don't exist.
Correct — __iter__ sets up state and returns self; __next__ yields values and raises StopIteration when done.
No such dunder.
__getitem__ enables indexing; for full iterator protocol you need __iter__ + __next__.
Recap: the iterator protocol requires both __iter__ (returns the iterator object) and __next__ (returns the next value or raises StopIteration).

What does __eq__ control?

Assignment is not an operator in the same sense; __eq__ is for ==.
Correct — without __eq__, == compares object identity (same as is).
is always checks identity; you can't override it.
Hashing is controlled by __hash__, though __eq__ affects it too.
Recap: define __eq__ for value equality. If you define __eq__, Python sets __hash__ to None unless you also define it.

Implementing __add__ to return a new Vector (not modifying self) is good practice because

Vector doesn't inherit from ABC; this is a design choice.
Correct — operators should return new objects, like Python's built-in numbers do.
Python won't raise an error, but it's a bad pattern.
Immutability isn't inherently faster; it's about correctness.
Recap: arithmetic operators should return new instances. v1 + v2 returns a new Vector; v1 is unchanged. Mirrors how 1 + 2 works with ints.

← PreviousNext →