List comprehensions
A list comprehension builds a new list in one line by transforming and/or filtering another sequence. It's the compact form of the build-a-list loop you saw earlier.
The shape is [expression for item in iterable]. The expression is what goes into the new list — often item itself, or something computed from it like item.upper() or n * n. Read it left-to-right: "give me expression for each item in iterable".
Add a trailing if condition to filter: [x for x in xs if keep(x)] only includes items that pass. Combine the two — transform *and* filter — like [n * n for n in nums if n % 2 == 0] (square the evens).
Use them for the simple, readable case. Don't force a comprehension when the logic gets gnarly — nested loops, multiple conditions, side effects, or an expression you can't read at a glance. At that point a plain for loop is clearer, and clarity wins. The same syntax also builds dict comprehensions {k: v for ...} and set comprehensions {x for ...}.
Syntax
[expression for item in iterable]
[expression for item in iterable if condition]
[w.upper() for w in words] # transform
[w for w in words if len(w) >= 4] # filter
[n * n for n in nums if n % 2 == 0] # both
{w: len(w) for w in words} # dict comprehension
{n % 3 for n in nums} # set comprehensionWorked examples
Transform every item
def upper_all(words):
return [word.upper() for word in words]
print(upper_all(["hello", "world"])) # ['HELLO', 'WORLD']Filter with a trailing if
def long_words(words, min_len):
return [w for w in words if len(w) >= min_len]
print(long_words(["cat", "elephant", "ox", "penguin"], 4))
# ['elephant', 'penguin']Transform and filter together (+ a dict comprehension)
def squares_of_evens(numbers):
return [n * n for n in numbers if n % 2 == 0]
print(squares_of_evens([1, 2, 3, 4, 5, 6])) # [4, 16, 36]
# Same syntax builds dicts:
words = ["a", "bb", "ccc"]
print({w: len(w) for w in words}) # {'a': 1, 'bb': 2, 'ccc': 3}Common mistakes & gotchas
The if goes at the END (to filter)
A filtering if comes after the for: [x for x in xs if cond]. If you need an if/else to *choose the value*, it goes before the for as a conditional expression: [a if cond else b for x in xs]. Mixing these up is a common SyntaxError.
Don't cram complex logic into a comprehension
If a comprehension grows nested loops, several conditions, or an expression you can't read in one pass, it's lost its only advantage — readability. Switch back to a plain for loop. Clever one-liners that nobody can read are a net loss.
Comprehensions are for building, not for side effects
Don't write [print(x) for x in xs] just to run print — you build a throwaway list of Nones. If you only want the side effect, use a normal for loop.
Why it matters
List comprehensions are idiomatic Python — you'll read them in nearly every codebase, so you must be fluent at both writing and decoding them. Used well they turn a five-line loop into one clear line; the skill is knowing when they help and when a plain loop is the kinder choice.