[Python-checkins] cpython (2.7): #13549: improve tutorial section about listcomps.

ezio.melotti python-checkins at python.org
Tue Dec 13 14:38:29 CET 2011


http://hg.python.org/cpython/rev/132158b287d7
changeset:   73951:132158b287d7
branch:      2.7
parent:      73944:bf7329190ca6
user:        Ezio Melotti <ezio.melotti at gmail.com>
date:        Tue Dec 13 14:50:21 2011 +0200
summary:
  #13549: improve tutorial section about listcomps.

files:
  Doc/tutorial/datastructures.rst |  167 +++++++++++++------
  1 files changed, 109 insertions(+), 58 deletions(-)


diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst
--- a/Doc/tutorial/datastructures.rst
+++ b/Doc/tutorial/datastructures.rst
@@ -235,89 +235,139 @@
 List Comprehensions
 -------------------
 
-List comprehensions provide a concise way to create lists without resorting to
-use of :func:`map`, :func:`filter` and/or :keyword:`lambda`. The resulting list
-definition tends often to be clearer than lists built using those constructs.
-Each list comprehension consists of an expression followed by a :keyword:`for`
-clause, then zero or more :keyword:`for` or :keyword:`if` clauses.  The result
-will be a list resulting from evaluating the expression in the context of the
-:keyword:`for` and :keyword:`if` clauses which follow it.  If the expression
-would evaluate to a tuple, it must be parenthesized. ::
+List comprehensions provide a concise way to create lists.
+Common applications are to make new lists where each element is the result of
+some operations applied to each member of another sequence or iterable, or to
+create a subsequence of those elements that satisfy a certain condition.
 
+For example, assume we want to create a list of squares, like::
+
+   >>> squares = []
+   >>> for x in range(10):
+   ...     squares.append(x**2)
+   ...
+   >>> squares
+   [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
+
+We can obtain the same result with::
+
+   squares = [x**2 for x in range(10)]
+
+This is also equivalent to ``squares = map(lambda x: x**2, range(10))``,
+but it's more concise and readable.
+
+A list comprehension consists of brackets containing an expression followed
+by a :keyword:`for` clause, then zero or more :keyword:`for` or :keyword:`if`
+clauses.  The result will be a new list resulting from evaluating the expression
+in the context of the :keyword:`for` and :keyword:`if` clauses which follow it.
+For example, this listcomp combines the elements of two lists if they are not
+equal::
+
+   >>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
+   [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
+
+and it's equivalent to:
+
+   >>> combs = []
+   >>> for x in [1,2,3]:
+   ...     for y in [3,1,4]:
+   ...         if x != y:
+   ...             combs.append((x, y))
+   ...
+   >>> combs
+   [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
+
+Note how the order of the :keyword:`for` and :keyword:`if` statements is the
+same in both these snippets.
+
+If the expression is a tuple (e.g. the ``(x, y)`` in the previous example),
+it must be parenthesized. ::
+
+   >>> vec = [-4, -2, 0, 2, 4]
+   >>> # create a new list with the values doubled
+   >>> [x*2 for x in vec]
+   [-8, -4, 0, 4, 8]
+   >>> # filter the list to exclude negative numbers
+   >>> [x for x in vec if x >= 0]
+   [0, 2, 4]
+   >>> # apply a function to all the elements
+   >>> [abs(x) for x in vec]
+   [4, 2, 0, 2, 4]
+   >>> # call a method on each element
    >>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
    >>> [weapon.strip() for weapon in freshfruit]
    ['banana', 'loganberry', 'passion fruit']
-   >>> vec = [2, 4, 6]
-   >>> [3*x for x in vec]
-   [6, 12, 18]
-   >>> [3*x for x in vec if x > 3]
-   [12, 18]
-   >>> [3*x for x in vec if x < 2]
-   []
-   >>> [[x,x**2] for x in vec]
-   [[2, 4], [4, 16], [6, 36]]
-   >>> [x, x**2 for x in vec]  # error - parens required for tuples
-     File "<stdin>", line 1, in ?
-       [x, x**2 for x in vec]
+   >>> # create a list of 2-tuples like (number, square)
+   >>> [(x, x**2) for x in range(6)]
+   [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
+   >>> # the tuple must be parenthesized, otherwise an error is raised
+   >>> [x, x**2 for x in range(6)]
+     File "<stdin>", line 1
+       [x, x**2 for x in range(6)]
                   ^
    SyntaxError: invalid syntax
-   >>> [(x, x**2) for x in vec]
-   [(2, 4), (4, 16), (6, 36)]
-   >>> vec1 = [2, 4, 6]
-   >>> vec2 = [4, 3, -9]
-   >>> [x*y for x in vec1 for y in vec2]
-   [8, 6, -18, 16, 12, -36, 24, 18, -54]
-   >>> [x+y for x in vec1 for y in vec2]
-   [6, 5, -7, 8, 7, -5, 10, 9, -3]
-   >>> [vec1[i]*vec2[i] for i in range(len(vec1))]
-   [8, 12, -54]
+   >>> # flatten a list using a listcomp with two 'for'
+   >>> vec = [[1,2,3], [4,5,6], [7,8,9]]
+   >>> [num for elem in vec for num in elem]
+   [1, 2, 3, 4, 5, 6, 7, 8, 9]
 
-List comprehensions are much more flexible than :func:`map` and can be applied
-to complex expressions and nested functions::
+List comprehensions can contain complex expressions and nested functions::
 
-   >>> [str(round(355/113.0, i)) for i in range(1,6)]
+   >>> from math import pi
+   >>> [str(round(pi, i)) for i in range(1, 6)]
    ['3.1', '3.14', '3.142', '3.1416', '3.14159']
 
 
 Nested List Comprehensions
---------------------------
+''''''''''''''''''''''''''
 
-If you've got the stomach for it, list comprehensions can be nested. They are a
-powerful tool but -- like all powerful tools -- they need to be used carefully,
-if at all.
+The initial expression in a list comprehension can be any arbitrary expression,
+including another list comprehension.
 
-Consider the following example of a 3x3 matrix held as a list containing three
-lists, one list per row::
+Consider the following example of a 3x4 matrix implemented as a list of
+3 lists of length 4::
 
-    >>> mat = [
-    ...        [1, 2, 3],
-    ...        [4, 5, 6],
-    ...        [7, 8, 9],
-    ...       ]
+   >>> matrix = [
+   ...     [1, 2, 3, 4],
+   ...     [5, 6, 7, 8],
+   ...     [9, 10, 11, 12],
+   ... ]
 
-Now, if you wanted to swap rows and columns, you could use a list
-comprehension::
+The following list comprehension will transpose rows and columns::
 
-    >>> print [[row[i] for row in mat] for i in [0, 1, 2]]
-    [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
+   >>> [[row[i] for row in matrix] for i in range(4)]
+   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
 
-Special care has to be taken for the *nested* list comprehension:
+As we saw in the previous section, the nested listcomp is evaluated in
+the context of the :keyword:`for` that follows it, so this example is
+equivalent to::
 
-    To avoid apprehension when nesting list comprehensions, read from right to
-    left.
+   >>> transposed = []
+   >>> for i in range(4):
+   ...     transposed.append([row[i] for row in matrix])
+   ...
+   >>> transposed
+   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
 
-A more verbose version of this snippet shows the flow explicitly::
+which, in turn, is the same as::
 
-    for i in [0, 1, 2]:
-        for row in mat:
-            print row[i],
-        print
+   >>> transposed = []
+   >>> for i in range(4):
+   ...     # the following 3 lines implement the nested listcomp
+   ...     transposed_row = []
+   ...     for row in matrix:
+   ...         transposed_row.append(row[i])
+   ...     transposed.append(transposed_row)
+   ...
+   >>> transposed
+   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
 
-In real world, you should prefer built-in functions to complex flow statements.
+
+In the real world, you should prefer built-in functions to complex flow statements.
 The :func:`zip` function would do a great job for this use case::
 
-    >>> zip(*mat)
-    [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
+   >>> zip(*matrix)
+   [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
 
 See :ref:`tut-unpacking-arguments` for details on the asterisk in this line.
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list