One Line, One Idea
You've already written the pattern several times: start with an empty list, loop over something, maybe filter, and append to the result.
A list comprehension says the same thing in one line:
Read it left to right: "a new list consisting of n * 2, for each n in numbers." The structure is [expression for item in iterable].
This isn't a Python-specific trick — it's called a comprehension because you're describing what goes into the new list, declaratively, rather than writing out the mechanics of how to build it.
Adding a Filter
Drop an if clause after the loop part to filter:
Read the second one as: "n * n for each n in numbers, but only if n is odd."
The equivalent loop:
Both are fine. The comprehension is shorter and, once you've read a few, actually easier to scan because the intent is right there in one line.
Combined Map and Filter
You can read values through a function and filter at the same time:
For each word longer than 3 letters, include its uppercase version.
Nested Loops in a Comprehension
Two fors produce a cartesian-product style pair:
The order is the same as if you'd nested the loops: the first for is the outer, the second the inner. It reads left-to-right like the equivalent indented loop.
Two levels is about the limit before a regular loop reads better. If you hit three, switch back to loops.
Dictionary and Set Comprehensions
Same idea, different braces:
Set comprehensions look identical to dict comprehensions at first glance — the difference is the key: value vs just a single expression. Braces plus : = dict; braces with no : = set.
Generator Expressions
A near-twin of list comprehension, but with parentheses instead of brackets — and crucially, it doesn't build a list:
Notice that we passed the generator directly to sum() and any() — no extra parentheses. Generator expressions are the right tool when the caller only needs to iterate once. They're more memory-friendly than a full list for large collections.
When to Use a Regular Loop Instead
Comprehensions are seductive. You can technically cram a lot into one. You shouldn't.
Reach for a plain loop when:
- The transformation is more than one step. If you need intermediate variables, write it out.
- There's complex error handling or branching.
- Anyone reading the line has to pause more than once to understand it.
The rule I apply: if I can read the comprehension in a single breath and understand what it does, it stays. If I stumble, I rewrite it as a loop.
Some comprehensions look clever but hurt:
Same result. The loop version is five lines instead of one, but "longer" isn't the same as "worse."
A Few Patterns You'll Reuse
Those five patterns cover a surprising amount of everyday data work.
Next Up
You've now seen the main collection types and the comprehension that binds them together. Next chapter: functions — packaging behavior into named, reusable units.
Frequently Asked Questions
What is a list comprehension in Python?
A compact syntax for building a new list from an existing iterable. [x * 2 for x in numbers] creates a new list with each number doubled. You can also filter: [x for x in numbers if x > 0].
When should I not use a list comprehension?
When it hurts readability. If the expression inside is complex or deeply nested, a regular for loop with proper variable names is clearer. Comprehensions are for simple transforms — mapping and filtering. Anything more complex is better in a full loop.
What's the difference between a list comprehension and a generator expression?
A list comprehension builds the whole list in memory. A generator expression (same syntax but with parentheses) yields one item at a time. Use a generator when you're feeding the results to something that iterates once — like sum(...) — so you don't materialize a list you'll immediately throw away.