Tutorial: Comprehensions, Iterators, and Iterables
Authors: Florent Hivert <[email protected]> and Nicolas M. Thiéry <nthiery at users.sf.net>List comprehensions
List comprehensions are a very handy way to construct lists in Python. You can use either of the following idioms:
[ [removed] for [removed] in [removed] ] [ [removed] for [removed] in [removed] if [removed] ]
For example, here are some lists of squares:
And a variant on the latter:
Exercises
Construct the list of the squares of the prime integers between 1 and 10:
Construct the list of the perfect squares less than 100 (hint: use :func:`srange` to get a list of Sage integers together with the method i.sqrtrem()):
System Message: ERROR/3 (<string>, line 40); backlink
Unknown interpreted text role "func".
One can use more than one iterable in a list comprehension:
Warning
Mind the order of the nested loop in the previous expression.
If instead one wants to build a list of lists, one can use nested lists as in:
Exercises
Compute the list of pairs of non negative integers such that i is at most , j is at most 8, and i and j are co-prime:
Compute the same list for :
Iterators
Definition
To build a comprehension, Python actually uses an iterator. This is a device which runs through a bunch of objects, returning one at each call to the next method. Iterators are built using parentheses:
You can get the list of the results that are not yet consumed:
Asking for more elements triggers a StopIteration exception:
An iterator can be used as argument for a function. The two following idioms give the same results; however, the second idiom is much more memory efficient (for large examples) as it does not expand any list in memory:
Exercises
Compute the sum of for all even :
Compute the sum of the gcd's of all co-prime numbers for :
Typical usage of iterators
Iterators are very handy with the functions :func:`all`, :func:`any`, and :func:`exists`:
System Message: ERROR/3 (<string>, line 139); backlink
Unknown interpreted text role "func".System Message: ERROR/3 (<string>, line 139); backlink
Unknown interpreted text role "func".System Message: ERROR/3 (<string>, line 139); backlink
Unknown interpreted text role "func".Let's check that all the prime numbers larger than 2 are odd:
It is well know that if 2^p-1 is prime then p is prime:
The converse is not true:
Using a list would be much slower here:
You can get the counterexample using :func:`exists`. It takes two arguments: an iterator and a function which tests the property that should hold:
System Message: ERROR/3 (<string>, line 181); backlink
Unknown interpreted text role "func".An alternative way to achieve this is:
Exercises
Build the list . Can you find two of those cubes and such that ?
itertools
At its name suggests :mod:`itertools` is a module which defines several handy tools for manipulating iterators:
System Message: ERROR/3 (<string>, line 206); backlink
Unknown interpreted text role "mod".The same results can be obtained using :func:`enumerate`:
System Message: ERROR/3 (<string>, line 213); backlink
Unknown interpreted text role "func".Here is the analogue of list slicing:
The functions :func:`map` and :func:`filter` also have an analogue:
System Message: ERROR/3 (<string>, line 229); backlink
Unknown interpreted text role "func".System Message: ERROR/3 (<string>, line 229); backlink
Unknown interpreted text role "func".Exercises
Define an iterator for the -th prime for :
Defining new iterators
One can very easily write new iterators using the keyword yield. The following function does nothing interesting beyond demonstrating the use of yield:
Iterators can be recursive:
Here is another recursive iterator:
Exercises
Write an iterator with two parameters , iterating through the set of nondecreasing lists of integers smaller than of length :
Standard Iterables
Finally, many standard Python and Sage objects are iterable; that is one may iterate through their elements:
Beware of infinite loops:
Infinite loops can nevertheless be very useful: