6 Nonlocal, Iterators, and Generators
2 Iterators
>>> a = [1, 2]
>>> a_iter = iter(a)
>>> next(a_iter)
1
>>> next(a_iter)
2
>>> next(a_iter)
StopIteration
An iterable is a data type which contains a collection of values which can be
processed one by one sequentially. Some examples of iterables we’ve seen include
lists, tuples, strings, and dictionaries. In general, any object that can be iterated
over in a for loop can be considered an iterable.
While an iterable contains values that can be iterated over, we need another type of
object called an iterator to actually retrieve values contained in an iterable. Calling
the iter function on an iterable will create an iterator over that iterable. Each
iterator keeps track of its position within the iterable. Calling the next function
on an iterator will give the current value in the iterable and move the iterator’s
position to the next value.
In this way, the relationship between an iterable and an iterator is analogous to the
relationship between a book and a bookmark - an iterable contains the data that is
being iterated over, and an iterator keeps track of your position within that data.
Once an iterator has returned all the values in an iterable, subsequent calls to next
on that iterable will result in a StopIteration exception. In order to be able to
access the values in the iterable a second time, you would have to create a second
iterator. One important application of iterables and iterators is the for loop. We’ve
counts = [1, 2, 3]
for i in counts:
print(i)
# equivalent to following pseudocode
# items = iter(counts)
# while True
# if next(items) errors
# exit the loop
# i = the value that returned
# print(i)
seen how we can use for loops to iterate over iterables like lists and dictionaries.
This only works because the for loop implicitly creates an iterator using the built-
in iter function. Python then calls next repeatedly on the iterator, until it raises
StopIteration.
The code to the right shows how we can mimic the behavior of for loops using
while loops.
Note that most iterators are also iterables - that is, calling iter on them will return
an iterator. This means that we can use them inside for loops. However, calling
iter on most iterators will not create a new iterator - instead, it will simply return
the same iterator.
We can also iterate over iterables in a list comprehension or pass in an iterable to
the built-in function list in order to put the items of an iterable into a list.
In addition to the sequences we’ve learned, Python has some built-in ways to create
iterables and iterators. Here are a few useful ones:
• range(start, end) returns an iterable containing numbers from start to end-
1. If start is not provided, it defaults to 0.
• map(f, iterable) returns a new iterator containing the values resulting from
applying f to each value in iterable.
• filter(f, iterable) returns a new iterator containing only the values in
iterable for which f(value) returns True.
Note: This worksheet is a problem bank—most TAs will not cover all the problems in discussion section.