The Iterator Pattern in Python

Learn about the interface for iteration, as well as utilizing sequence objects as iterators.

Here, we will take a small detour from generators to understand iteration in Python more deeply. Generators are a particular case of iterable objects, but iteration in Python goes beyond generators, and being able to create good iterable objects will give us the chance to create more efficient, compact, and readable code.

In the previous code listings, we have seen examples of iterable objects that are also iterators because they implement both the __iter__() and __next__() magic methods. While this is fine in general, it's not strictly required that they always have to implement both methods, and here we'll show the subtle differences between an iterable object (one that implements __iter__) and an iterator (that implements __next__).

We also explore other topics related to iterations, such as sequences and container objects.

The interface for iteration

An iterable is an object that supports iteration, which, at a very high level, means that we can run a for .. in ...: loop over it, and it will work without any issues. However, iterable doesn't mean the same as iterator.

Generally speaking, an iterable is just something we can iterate, and it uses an iterator to do so. This means that in the __iter__ magic method, we would like to return an iterator, namely, an object with a __next__() method implemented.

An iterator is an object that only knows how to produce a series of values, one at a time, when it's being called by the already explored built-in next() function, while the iterator is not called. It's simply frozen, sitting idly by until it's called again for the next value to produce. In this sense, generators are iterators.

Get hands-on with 1200+ tech skills courses.