Skip to main content
Back to module
Python Fundamentals · Data Structures

Comprehensions

Reading35mLesson 3 of 3 in this module

What you'll learn

  • Build lists and dicts in one line
  • Filter items with an if at the end of a comprehension
  • Choose a value per item with if ... else at the front
  • Sum or count over a filter with a generator expression

Build lists, dictionaries and sets in one readable line, with optional filtering.

Why it matters

A huge share of everyday code follows one shape: start with an empty collection, loop over some data, maybe skip some items, and add a transformed value for each one. Python has a compact, readable syntax for exactly this, called a comprehension. You will see comprehensions everywhere in real Python code, especially in data work, so you need to be able to read and write them.

From loop to list comprehension

Here is the familiar loop version, squaring the numbers 1 to 5:

Python
squares = []
for n in range(1, 6):
    squares.append(n * n)
print(squares)    # [1, 4, 9, 16, 25]

The same thing as a list comprehension:

Python
squares = [n * n for n in range(1, 6)]

Read it left to right as "a list of n * n, for each n in range(1, 6)". The pieces map directly onto the loop: the expression that was inside append(...) comes first, then the for clause.

More examples:

Python
names = ["ada", "grace", "katherine"]
capitalised = [name.title() for name in names]    # ['Ada', 'Grace', 'Katherine']
lengths = [len(name) for name in names]           # [3, 5, 9]

celsius = [0, 21.5, 100]
fahrenheit = [c * 9 / 5 + 32 for c in celsius]    # [32.0, 70.7, 212.0]

texts = ["12.5", "13.0", "11.75"]
values = [float(t) for t in texts]                # [12.5, 13.0, 11.75]

That last one replaces a four-line loop you may have written in the debugging lesson.

Filtering with if

Add an if at the end to keep only some items:

Python
readings = [21.5, -999, 22.0, 23.25, -999, 22.75]

valid = [r for r in readings if r != -999]
print(valid)              # [21.5, 22.0, 23.25, 22.75]

evens = [n for n in range(10) if n % 2 == 0]
print(evens)              # [0, 2, 4, 6, 8]

The loop equivalent puts the if inside the for:

Python
valid = []
for r in readings:
    if r != -999:
        valid.append(r)

If you want to transform values conditionally rather than filter them, put an if ... else expression at the front instead:

Python
labels = ["high" if r > 22 else "normal" for r in valid]
# ['normal', 'normal', 'high', 'high']

Rule of thumb: if at the end filters (fewer items out); if ... else at the front chooses a value (same number of items out).

Dictionary comprehensions

Use braces and a key: value pair:

Python
names = ["ada", "grace", "katherine"]
name_lengths = {name: len(name) for name in names}
# {'ada': 3, 'grace': 5, 'katherine': 9}

scores = {"Ada": 91, "Grace": 48, "Katherine": 85, "Alan": 55}
passed = {name: s for name, s in scores.items() if s >= 50}
# {'Ada': 91, 'Katherine': 85, 'Alan': 55}

prices_usd = {"bolt": 0.10, "nut": 0.05}
prices_cents = {item: round(p * 100) for item, p in prices_usd.items()}
# {'bolt': 10, 'nut': 5}

Set comprehensions

Braces without a colon build a set, which removes duplicates:

Python
emails = ["ada@lab.org", "grace@navy.mil", "alan@lab.org"]
domains = {e.split("@")[1] for e in emails}
# {'lab.org', 'navy.mil'}

Nested loops in a comprehension

You can have more than one for, in the same order as nested loops:

Python
grid = [(row, col) for row in range(2) for col in range(3)]
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

matrix = [[1, 2], [3, 4], [5, 6]]
flat = [x for row in matrix for x in row]    # [1, 2, 3, 4, 5, 6]

These get hard to read quickly. If a comprehension needs two for clauses and an if, a regular loop is often kinder to the next reader.

Generator expressions

Swap the square brackets for parentheses inside a function call and you get a generator expression, which produces values one at a time without building a list in memory:

Python
total = sum(r for r in readings if r != -999)
count_high = sum(1 for r in readings if r > 22)

This is the usual way to sum or count over a filter.

When not to use a comprehension

  • When the loop body does more than build one value (printing, updating several variables, handling errors).
  • When the line gets long enough that you have to scroll or squint.
  • When you do not need the resulting list at all. Do not write [print(x) for x in items]; a plain for loop is clearer.

Common mistakes

  • Putting a filtering if at the front. [x if x > 0 for x in xs] is a SyntaxError. Filters go at the end: [x for x in xs if x > 0].
  • Forgetting the else in a front if. [a if cond else b for ...] needs both parts.
  • Reusing a name. [x for x in x] works but is confusing; use a different loop variable.
  • Writing a set by accident. {n for n in nums} is a set, not a dict; a dict needs key: value.

Quick recap

  • [expr for item in iterable] builds a list; add if cond at the end to filter.
  • {key: value for item in iterable} builds a dict; {expr for ...} builds a set.
  • expr_a if cond else expr_b at the front chooses a value for every item.
  • sum(... for ...) sums or counts without building a list.
  • Prefer a normal loop when a comprehension stops being easy to read.

Try it

In the Do tab you will rewrite three small loops as comprehensions: squares, a filter of passing scores, and a dictionary of word lengths.

Key terms (5)

comprehension
A one-line syntax that builds a list, dict or set from a loop, optionally filtering items.
list comprehension
A comprehension in square brackets, such as [n * n for n in nums], that builds a list.
Dictionary comprehensions
Comprehensions in braces with a key: value pair that build a dictionary.
Set comprehensions
Comprehensions in braces without a colon that build a set, removing duplicates.
generator expression
A comprehension in parentheses that produces values one at a time without building a list, often used inside sum().

Recap

  • [expr for item in iterable] builds a list; add if cond at the end to filter.
  • {key: value for item in iterable} builds a dict, and {expr for ...} builds a set.
  • An if ... else at the front chooses a value for every item instead of filtering.
  • sum(... for ...) sums or counts without building a list.
  • Use a normal loop when a comprehension stops being easy to read.
Also in this lesson: