Comprehensions

The Course
January 8, 2026
5 min read

You have written this shape several times already: make an empty list, loop, append. A comprehension says the same thing in one line.

The same result, two ways Python
prices = [4.99, 12.50, 3.25, 8.00]

# The loop you already know:
with_tax = []
for price in prices:
    with_tax.append(round(price * 1.2, 2))
print(with_tax)

# The comprehension:
with_tax = [round(price * 1.2, 2) for price in prices]
print(with_tax)

Read it left to right as English: the rounded price times 1.2, for each price in prices. The expression comes first because the result is what matters.

Filtering

Add if at the end to keep only some items.

Transform and filter Python
numbers = range(1, 21)

evens = [n for n in numbers if n % 2 == 0]
print(evens)

squares_of_odds = [n ** 2 for n in numbers if n % 2 == 1]
print(squares_of_odds)

words = ["apple", "fig", "banana", "kiwi", "cherry"]
long_words = [w.upper() for w in words if len(w) > 4]
print(long_words)

The order is always the same: what you want, for what you loop over, if what you keep.

if in front means something different

[x if x > 0 else 0 for x in values] is a conditional expression choosing the value, so it comes before the for. [x for x in values if x > 0] is a filter, so it comes after. Front means choose, back means keep.

Choose versus keep Python
values = [3, -1, 4, -5, 9]

print([v if v > 0 else 0 for v in values])    # replaces negatives with 0
print([v for v in values if v > 0])           # drops negatives entirely

Dictionary and set comprehensions

The same syntax with braces builds dictionaries and sets.

Beyond lists Python
words = ["apple", "fig", "banana"]

lengths = {word: len(word) for word in words}
print(lengths)

# Invert a dictionary in one line:
capitals = {"France": "Paris", "Japan": "Tokyo"}
print({city: country for country, city in capitals.items()})

# A set comprehension - duplicates collapse:
letters = {letter for word in words for letter in word}
print(sorted(letters))

That last one has two for clauses: they read in the same order you would write them as nested loops — outer first, inner second.

Generator expressions

Swap the brackets for parentheses and nothing is built in memory; values are produced one at a time, as needed.

Lazy by default Python
numbers = range(1, 1_000_001)

# A list of a million squares - all held in memory at once.
squares_list = [n ** 2 for n in numbers]
print(type(squares_list), len(squares_list))

# A generator - nothing computed yet.
squares_gen = (n ** 2 for n in numbers)
print(type(squares_gen))

# sum() consumes it one value at a time, using almost no memory.
print(sum(n ** 2 for n in range(1, 1001)))

When you pass a comprehension straight into sum, max, any or all, drop the brackets — the generator form does the same job without building a throwaway list.

any and all Python
passwords = ["hunter2", "correct-horse", "12345678"]

print(any(len(p) < 8 for p in passwords))       # is any too short?
print(all(len(p) >= 7 for p in passwords))      # are all long enough?
print(sum(1 for p in passwords if p.isdigit())) # count matching items
Readable beats clever

A comprehension should fit on one line and hold one idea. Once you are nesting three for clauses with two conditions, a plain loop is the kinder choice — for the next reader, and for you.

Exercise

Clean a data file

The list holds raw lines from a form. Produce a list of clean names — stripped of whitespace, title-cased, with blank entries dropped — then a dictionary mapping each name to its length.

raw = ["  ada lovelace ", "", "ALAN TURING", "   ", "grace hopper"]

# Your code here
Show one solution
raw = ["  ada lovelace ", "", "ALAN TURING", "   ", "grace hopper"]

names = [line.strip().title() for line in raw if line.strip()]
print(names)

lengths = {name: len(name) for name in names}
print(lengths)

if line.strip() uses truthiness from Day 2 — an empty or whitespace-only string is falsy, so those lines are dropped without a length check.

Day 4 is done

Functions and comprehensions are the two habits that most separate Python that reads well from Python that merely runs.

Tomorrow, the world pushes back: errors, files, and the standard library.

What you learned

  • [expression for item in iterable] builds a list in one line.
  • A trailing if filters; a leading if/else chooses a value.
  • {k: v for ...} and {v for ...} build dictionaries and sets.
  • (expression for item in iterable) is a lazy generator — ideal inside sum, any, all.
  • Keep them to one idea; reach for a loop when they stop reading cleanly.
Last updated on January 8, 2026

Was this article helpful?

Your response is saved on this device.