Functions, Iterators, and Generators
The final conversions and data extractions are more easily done with higher-order
functions such as map() and filter(). We'll return to those in Chapter 5,
Higher-order Functions.
Using lists, dicts, and sets
A Python sequence object, like a list, is iterable. However, it has some additional
features. We'll think of it as a materialized iterable. We've used the tuple() function
in several examples to collect the output of a generator expression or generator
function into a single tuple object. We can also materialize a sequence to create
a list object.
In Python, a list display offers simple syntax to materialize a generator: we just add the
[] brackets. This is ubiquitous to the point where the distinction between generator
expression and list comprehension is a subtlety of little practical importance.
The following is an example to enumerate the cases:
range(10)
range(0, 10)
[range(10)]
[range(0, 10)]
[x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
The first example is a generator function.
The range(10) function is lazy; it won't produce the 10 values
until evaluated in a context that iterates through the values.
The second example shows a list composed of a single generator function.
To evaluate this, we'll have to use nested loops. Something like this [x for
gen in [range(10)] for x in gen].
The third example shows a list comprehension built from a generator expression
that includes a generator function. The function, range(10), is evaluated by a
generator expression, x for x in range(10). The resulting values are collected
into a list object.
We can also use the list() function to build a list from an iterable or a generator
expression. This also works for set(), tuple(), and dict().