diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -235,14 +235,49 @@ 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. +List comprehensions provide a concise way to create lists without having to use +:meth:`list.append` in a :keyword:`for` loop, :func:`map`, :func:`filter`, +and/or :keyword:`lambda`. The resulting list definition tends often to be +clearer than lists built using those constructs. 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. + 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. :: +: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 examples. If the expression is a tuple (e.g. the ``(x, y)`` +in this example), it must be parenthesized. :: >>> freshfruit = [' banana', ' loganberry ', 'passion fruit '] >>> [weapon.strip() for weapon in freshfruit] @@ -275,43 +310,42 @@ List comprehensions are much more flexible than :func:`map` and can be applied to 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. +In a list comprehension might contain arbitrary expressions, including +other listcomps. Nested list comprehensions are a powerful tool +but -- like all powerful tools -- they need to be used carefully, if at all. Consider the following example of a 3x3 matrix held as a list containing three lists, one list per row:: - >>> mat = [ - ... [1, 2, 3], - ... [4, 5, 6], - ... [7, 8, 9], - ... ] + >>> mat = [ + ... [1, 2, 3], + ... [4, 5, 6], + ... [7, 8, 9], + ... ] -Now, if you wanted to swap rows and columns, you could use a list +Now, if you wanted to swap rows and columns, you could use this list comprehension:: - >>> 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 mat] for i in [0, 1, 2]] + [[1, 4, 7], [2, 5, 8], [3, 6, 9]] -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 the example is equivalent to:: - To avoid apprehension when nesting list comprehensions, read from right to - left. - -A more verbose version of this snippet shows the flow explicitly:: - - for i in [0, 1, 2]: - for row in mat: - print row[i], - print + >>> swapped = [] + >>> for i in [0, 1, 2]: + ... swapped.append([row[i] for row in mat]) + ... + >>> print swapped + [[1, 4, 7], [2, 5, 8], [3, 6, 9]] In 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::