Programming Fundamentals › Collections
Iterator
An object that yields items one at a time from a sequence.
Also known as: iterator protocol, iterable
An iterator is an object that gives you the items of a sequence one at a time. It exposes a way to ask for the next item, and it signals when there are none left. Many languages have this protocol, and it’s what a for loop uses behind the scenes.
In Python, an iterator defines __iter__ (returns itself) and __next__ (returns the next item, or raises StopIteration):
class Countdown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current + 1
list(Countdown(3)) # [3, 2, 1]
An iterable is different from an iterator: it can produce an iterator (through __iter__), and so it can be looped over more than once. A list is iterable. An iterator is usually single-pass, so once it’s exhausted, looping over it again gives nothing. With c = Countdown(2), the first list(c) gives [2, 1] and a second list(c) gives [].
Writing an iterator class by hand is verbose. A generator gives you the same behaviour with much less code, and that’s usually the better choice. Write a class-based iterator when you need extra methods, such as a reset or a way to peek ahead, or when the object has to be both the sequence and the cursor over it.
The classic mistake is modifying a collection while iterating over it, such as removing items from a list in a for loop. Items get skipped, and the result looks almost right. Build a new collection instead, or iterate over a copy.