Iteration as an Interface · practice
Understand the Iterator Protocol
iter() and next() are the caller’s side. This lesson is the other side: what an
It is two
The two methods
__iter__ returns an iter() and every for
__next__ returns the next item, or raises StopIteration when there are none left. Python calls it when something asks for an item, which next() does.
An __iter__. An iterator defines both, and its __iter__ returns itself.
Here is the smallest complete example:
No __next__ produces them, and the for loop neither knows nor cares.
Reading it slowly
__iter__ returns self, which is the definition of an iterator: it is the walker, so asking it for one hands back itself. That is the same iter(x) is x you tested in Lesson 1.
__next__ does the work. It checks whether there is anything left, raises StopIteration if not, moves the position, and returns the item. Every iterator ever written has that shape.
Notice what happens on a second pass:
Exhausted, exactly like the list iterator in Lesson 1. Countdown holds its position in self.current, and nothing resets it. It is an iterator, so it is single use.
What must __next__ do when there is nothing left?
Iterable and iterator as separate objects
Countdown is both at once, which is why it is used up. When an object should be re-iterable, keep the two apart: the iterable makes a new iterator each time.
Both passes see both items, because each list() call got a fresh BankWalker with its own _index. The bank holds the data; the walker holds the position. That is exactly the arrangement a list has with its own iterator, and now you can see why.
Do not write this
Two classes and about twenty lines to walk a list you already have. In real code, almost never.
This lesson exists so the protocol is concrete rather than a description, and the next two lessons show what you actually write instead: __iter__ that delegates to something already iterable, and generators, which produce this whole shape from an ordinary
The exercise builds one full iterator by hand, once.
Task
Write the protocol by hand, once, so it stops being a description.
Countdown(start) is an start, start - 1, down to 1, and then stops. It defines both __iter__ returns itself, and __next__ produces the next number or raises StopIteration. A Countdown(0) produces nothing at all.
ScoreLog(scores) is an __iter__ returns a new LogWalker each time it is asked, so the same log can be walked twice.
LogWalker(scores) is the iterator: it holds the position, returns itself from __iter__, and raises StopIteration once it passes the end.
The grader walks a ScoreLog twice and expects both passes to see everything, and walks a Countdown twice and expects the second to be empty. That difference is the whole point.