You have written this shape several times already: make an empty list, loop, append. A comprehension says the same thing in one line.
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.
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.
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 entirelyDictionary and set comprehensions
The same syntax with braces builds dictionaries and sets.
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.
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.
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 itemsReadable 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.
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 hereShow 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
iffilters; a leadingif/elsechooses a value. {k: v for ...}and{v for ...}build dictionaries and sets.(expression for item in iterable)is a lazy generator — ideal insidesum,any,all.- Keep them to one idea; reach for a loop when they stop reading cleanly.