HeadlinesBriefing favicon HeadlinesBriefing.com

Python for Loop Iterator Protocol Explained

Hacker News •
×

There are certain Python features so straightforward you forget they're doing anything. Consider `for x in y`. You write a list, string, or range, and Python hands back one item at a time. No index variable, no bounds checks. For a long time, I treated `for x in y` as just syntax meaning “loop over this thing.” Then I started building Memphis, my Python interpreter in Rust, and had to answer: What is a for loop actually doing?

The answer is both simpler and more involved. Python does not loop over the collection directly; it loops over an iterator. When Python sees `for x in [10, 20, 30]`, it effectively runs `it = iter([10, 20, 30])` then repeatedly calls `next(it)` until StopIteration is raised. The `for` syntax is just a pretty wrapper around this protocol.

This explains why `for` works on lists, strings, ranges, and generators—each produces an iterator. In Memphis, my treewalk interpreter handles a `for` loop by evaluating the right-hand expression, calling `iter(...)`, repeatedly calling `next(...)`, binding each value, and stopping on StopIteration. The loop itself knows nothing about specific types; it only needs the iterator protocol.

The key shift: `for x in y` does not mean “loop over y.” It means “ask y how to be iterated.” Once you see this, Python’s iteration model feels unified, not magical. Generators, custom iterables, and exhausted-iterator bugs all become clear.