Iteration as an Interface · practice
Use iter() and next()
A for
Driving a loop by hand
iter() asks for the next() asks it for one item and moves it forward. That is the entire protocol on the caller’s side.
Ask once more and the iterator has to say something:
next(walker)
StopIteration. Not a bug, not an error in your code: it is how an iterator reports that there is nothing left. The
What for is doing
Knowing those two calls, you can write the loop out longhand:
Same output as for question in questions. Every for loop you have ever written is this, and this is why a for loop never raises StopIteration at you: catching it and stopping is the loop’s job.
What does a for loop do with StopIteration?
A default instead of an exception
next() takes a second
This is worth knowing because it turns “take the next thing, if there is one” from four lines into one. It is the right tool when running out is an ordinary outcome, and the wrong one when running out means something went wrong and you want to hear about it.
What this is actually for
Most of the time you should write for, and this lesson is not an argument otherwise. Reaching for iter() and next() directly is worth it in a few real situations:
Taking one item, then looping over the rest. A file’s first line is a header, and the rest are data:
lines = iter(all_lines)
header = next(lines)
for line in lines:
...
The for loop continues from where next() left the position, because there is one iterator and both share it. That only works because of the split from Lesson 1.
Taking one item safely. next(walker, None) answers “is there anything?” and hands you that item at the same time. The iterator advances; this is a read, not a peek.
Walking two sequences at different speeds. When zip() does not fit because one side sometimes advances twice.
If you find yourself writing while True with a try around next(), you have rewritten for. Write for.
Task
Use iter() and next() directly for the three jobs where they earn their place.
split_header(lines) returns the first line and a next(), then (None, []).
first_or(items, fallback) returns the first item, or fallback when there is none. Use the two-next() rather than a try.
count_by_hand(items) counts the items using while True, next(), and except StopIteration rather than a for loop. You would not write this in real code, and writing it once is how the loop stops being magic.
Run the program and check that split_header returns the remaining two lines, not all three.