Execute Program

Python for Programmers: Comprehensions

Welcome to the Comprehensions lesson!

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • We often need to transform every element in a list.

  • >
    numbers = [0, 1, 2]
    transformed_data = []
    for n in numbers:
    transformed_data.append(n + 10)
    transformed_data
    Result:
    [10, 11, 12]Pass Icon
  • The example below uses a "list comprehension" to get the same result as above, but with much less code.

  • >
    numbers = [0, 1, 2]
    transformed_data = [n + 10 for n in numbers]
    transformed_data
    Result:
    [10, 11, 12]Pass Icon
  • The square brackets make this a list comprehension (as opposed to other kinds of comprehensions that we'll see later). List comprehensions always result in a list. However, a comprehension can iterate over any iterable as its data source, not just lists. For example, comprehensions can iterate over ranges.

  • >
    [value * 2 for value in range(3)]
    Result:
  • >
    [value + 10 for value in range(6)]
    Result:
    [10, 11, 12, 13, 14, 15]Pass Icon
  • We can filter out elements by adding an if some_condition clause at the end. If the condition is true, that value is included. If it's false, the value is skipped over. (In the next example value % 2 is only True for even numbers.)

  • >
    [value + 10 for value in range(6) if value % 2 == 0]
    Result:
    [10, 12, 14]Pass Icon
  • >
    names = ["Amir", "Betty", "Cindy"]
    ends_in_y = [name for name in names if name.endswith("y")]
    ends_in_y
    Result:
    ['Betty', 'Cindy']Pass Icon
  • Comprehensions can iterate over multiple iterables, similar to when we nest multiple for loops. Here are two nested for loops looping over integers and strings, producing all possible pairings of the integers and strings.

  • >
    integers = [0, 1]
    strings = ["a", "b"]
  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    pairs = []
    for integer in integers:
    for string in strings:
    pairs.append((integer, string))
    pairs
    Result:
  • Now here's the comprehension version. Note the nice symmetry with the loop syntax: the for integer in integers and for string in strings are the same in the loop and comprehension versions.

  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    pairs = [(integer, string)
    for integer in integers
    for string in strings]
    pairs
    Result:
  • We can even collapse the comprehension into a single line, though that makes it harder to read in this case.

  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    [(integer, string) for integer in integers for string in strings]
    Result:
  • The symmetry between for loops and comprehensions extends to iteration order as well. With a for loop or a comprehension, we'll get different results if we iterate over strings first, as opposed to iterating over numbers first.

  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    [(integer, string)
    for string in strings
    for integer in integers]
    Result:
  • We can also use comprehensions to build dictionaries. To do this, we wrap the comprehension in {} instead of []. We specify each key and value pair with key: value.

  • >
    items = [("a", 1), ("b", 2)]
    {item[0]: item[1]
    for item in items}
    Result:
    {'a': 1, 'b': 2}Pass Icon
  • In that example, the item[0]: item[1] part could be more clear. item[0] is the key, and item[1] is the value. It would be better if the comprehension started with {key: value. We can use the unpacking syntax to achieve that.

  • >
    items = [("a", 1), ("b", 2)]
    {key: value
    for key, value in items}
    Result:
    {'a': 1, 'b': 2}Pass Icon
  • All other details of dictionary comprehensions match what we saw for list comprehensions. They can have multiple fors and they can have ifs.

  • Comprehensions are a relatively unique feature of Python. That makes them fun, but it also brings a danger: the novelty can lead us to overuse them.

  • We recommend using comprehensions, but watching for complex comprehensions that become unwieldy. Sometimes a loop is easier to read, even if it takes a few more lines. Readability is more important than line count!

  • Here's a code problem:

    Use a list comprehension to write a double_numbers function. It should take a list, and return a new list with all of the numbers doubled. You can solve this with a one-line list comprehension!

    def double_numbers(numbers):
    return [2 * n for n in numbers]
    assert double_numbers([]) == []
    assert double_numbers([2, 4, 6]) == [4, 8, 12]
    assert double_numbers([-1, 3, 5]) == [-2, 6, 10]
    Goal:
    None
    Yours:
    NonePass Icon