Generator Comprehensions

Sum

Python has a number of functions that act on iterables. List comprehensions return an iterable so we can pass list comprehensions straight into a one of these functions.

Let’s try out the sum function:

>>> numbers = [1, 2, 3, 4]
>>> sum(numbers)
10

Let’s sum the squares of all of the numbers in our numbers list. We can use a list comprehension:

>>> sum([n ** 2 for n in numbers])
30

Cool!

Generators

We can use sum with tuples, sets, and any other iterable:

>>> sum((8, 9, 7))
24
>>> sum({8, 9, 7})
24

Sometimes we don’t really care if a list comprehension returns a list, or some other kind of iterable. When we passed a list comprehension into sum, we only really needed to pass in an iterable, not necessarily a list.

Let’s use a generator expression instead of a list comprehension. We can make a generator expression like this:

>>> squares = (n ** 2 for n in numbers)
>>> squares
<generator object <genexpr> at 0x7f733d4f7e10>

We can use a generator in our sum call like this:

>>> sum((n ** 2 for n in numbers))
30

When our generator expression is already in parentheses, we can leave off the redundant parentheses:

>>> sum(n ** 2 for n in numbers)
30

Generators don’t work like the other iterables we’ve learned about so far.

>>> squares[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'generator' object is not subscriptable

You can not use item indexes to get values from generators.

You also can’t ask generators for their length:

>>> len(squares)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'generator' has no len()

You can loop over generators:

>>> for s in squares:
...     print(s)
...
1
4
9
16

But only once:

>>> for s in squares:
...     print(s)
...

Generators are single-use iterables. You can get items from a generator by using the built-in next function:

>>> squares = (n ** 2 for n in numbers)
>>> next(squares)
1
>>> next(squares)
4
>>> next(squares)
9
>>> next(squares)
16
>>> next(squares)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

We’ll go into more detail about generators more in a future class.

Iteration Tools

Let’s learn some more built-in functions for working with iterators.

If we want to make sure everything in our list conforms to a certain rule, we can use the all function for that.

>>> all(n > 1 for n in numbers)
False
>>> all(n > 0 for n in numbers)
True

If we want to only make sure that some of our list conforms to a certain rule, we can use the any function.

>>> any(n > 2 for n in numbers)
True
>>> any(n < 1 for n in numbers)
False

If we want to find the smallest or largest value in a collection, we can use min or max:

>>> min(numbers)
1
>>> max(numbers)
4