Module 2: Lazy Pipelines and First-Class Behavior

Iterator Protocol from First Principles

Iterator Protocol from First Principles

A for loop obtains an iterator, repeatedly calls next, and stops when StopIteration is raised. Iterable objects can create independent iterators; iterator objects track one traversal state and are normally single-use.

Module: Module 2: Lazy Pipelines and First-Class Behavior

Core mental model

This lesson is built around four connected ideas. Read them as a decision framework, then prove each one with the walkthrough.

  • __iter__ returns an iterator and __next__ produces one value at a time.
  • An iterator returns itself from __iter__ and becomes exhausted.
  • A reusable iterable should create fresh independent iterator state.
  • Files, ranges, generators, and many library objects share this protocol.

Walkthrough

class CountRange:
    def __init__(self, start, stop):
        self.start = start
        self.stop = stop

    def __iter__(self):
        current = self.start
        while current < self.stop:
            yield current
            current += 1

values = CountRange(2, 5)
print(list(values))
print(list(values))

CountRange is a reusable iterable because each __iter__ call creates a new generator with independent current state. Making the collection itself its iterator would make repeated and nested iteration interfere.

Hands-on lab

Implement a replayable Windowed iterable over a source sequence and test two simultaneous iterators. Then compare it with a deliberately single-use iterator.

What to watch for

  • Reusing an exhausted iterator produces no new values.
  • Storing current traversal state on a reusable collection breaks nested loops.
  • An infinite iterator requires a caller-side stopping condition.

Engineering checklist

  • Connect the lesson's mental model to the choices made in the walkthrough.
  • Test the normal case, an empty or boundary case, and one invalid case.
  • Keep external input, side effects, and reusable logic in clearly separated layers.
  • Prefer the clearest correct implementation before optimizing or generalizing it.

Completion check

You can implement the lab without copying the example, explain the core concepts in your own words, and show tests or terminal output that demonstrate the expected and failure paths.