List Comprehensions
Overview
A list comprehension is an expression that builds a new list by transforming and optionally filtering items from an iterable, all in a single line. The syntax is: [expression for item in iterable] [expression for item in iterable if condition] Python evaluates it by iterating over the iterable, optionally testing the condition, and collecting the `expression` result into a new `list`. It is exactly equivalent to writing a `for` loop that calls `.append()` on an empty `list`, but more concise and often faster because the append is handled internally by the interpreter. Concrete examples: status_codes = [200, 404, 200, 500, 301] ok_codes = [code for code in status_codes if code == 200] # ok_codes -> [200, 200] usernames = ['alice', 'bob', 'carol'] upper_names = [name.upper() for name in usernames] # upper_names -> ['ALICE', 'BOB', 'CAROL'] prices = [9.99, 24.50, 3.75, 49.00] discounted = [round(p * 0.9, 2) for p in prices] # discounted -> [9.0, 22.05, 3.38, 44.1] You can call any function in the `expression` part — `str.upper()`, `round()`, or your own helpers. The `if` clause is optional; without it, every item is included. Think of a list comprehension as a factory conveyor belt: items roll in from the iterable, a filter gate (the `if` clause) drops items that fail the test, and each surviving item is reshaped by the `expression` before landing in the output bin. Back in Python, the "conveyor belt" is the `for` clause, the "gate" is the optional `if` clause, and the "reshaping step" is the `expression`. Readability rule: keep comprehensions to one readable line. If you need nested loops, multiple conditions, or side effects, use a regular `for` loop instead. matrix = [[1, 2], [3, 4]] # Trap: order is outer-first, matching normal loops, not inner-first flat = [x for row in matrix for x in row] When dealing with nested comprehensions, the loop order can be extremely counter-intuitive. This is covered fully in nested-comprehensions.
List comprehensions replace the repetitive pattern of creating an empty `list`, looping, and calling `.append()` — the most common list-building pattern in Python. They make data-transformation code shorter, more declarative, and often faster. Mastering them is essential because they appear everywhere in production Python code.
Where used: Transforming API response lists, Filtering database query results, Building FastAPI response payloads, Data pipeline transformations
Why learn this
- Write concise data transforms when building FastAPI response payloads from database rows
- Read and maintain real codebases faster — comprehensions are used more often than explicit `.append()` loops
- Unlocks `dict`/`set` comprehensions and generator expressions, which follow the same syntax pattern
Code walkthrough
status_codes = [200, 404, 200, 500, 301]
# Equivalent for-loop
ok_loop = []
for code in status_codes:
if code == 200:
ok_loop.append(code)
# Same result with a comprehension
ok_comp = [code for code in status_codes if code == 200]
print('loop:', ok_loop)
print('comp:', ok_comp)
Focus: Both produce the same `list` — the comprehension collapses the loop, condition, and `.append()` into one expression.
Aha moment
tags = ['python', 'fastapi', 'sql', 'python', 'docker']
unique_sorted = sorted([t for t in tags if t != 'sql'])
original = tags
print('result:', unique_sorted)
print('original:', original)
print('same object?', unique_sorted is original)
Prediction: Does the comprehension modify the original `tags` list?
Common guess: Yes, it removes 'sql' from tags
A comprehension always builds a brand-new `list` — it never mutates the source iterable. The original `list` is untouched, and `is` confirms they are different objects.
Common mistakes
- Using a comprehension for side effects: Comprehensions build a new `list`. Writing `[print(x) for x in items]` works but wastes memory on a list of `None` values and confuses readers. Use a regular `for` loop when you only need side effects.
- Overlong comprehensions that hurt readability: Cramming nested loops, multiple conditions, or complex expressions into one comprehension makes it unreadable. If the comprehension does not fit on one line comfortably, break it into a regular `for` loop.
- Forgetting that the result is a new list: A comprehension never mutates the original iterable — it always creates a fresh `list`. If you discard the return value, the work is wasted.
- Putting the if clause in the wrong position: A filtering `if` goes AFTER the `for` clause: `[x for x in items if x > 0]`. Putting it before the `for` is a syntax error unless you are writing a ternary expression, which is a different pattern: `[x if x > 0 else 0 for x in items]`.
Glossary
- iterable
- Any collection or data structure in Python that you can loop through one item at a time, like a list or a string, e.g. `for x in [1, 2, 3]`.
- declarative
- A style of programming where you describe what you want the result to be, rather than writing the step-by-step instructions on how to get it, e.g. `[x*2 for x in nums]` instead of a manual append loop.
Recall questions
- What is the general syntax of a list comprehension, and which part is optional?
- What equivalent pattern does a list comprehension replace?
- Why are list comprehensions often faster than the equivalent `for` loop with `.append()`?
- When should you use a regular for-loop instead of a comprehension?
- In a flattened list comprehension with multiple `for` clauses, what order do the loops follow?
Understanding checks
What is the output of this list comprehension?
['alice', 'carol']
The `if n.isupper()` clause filters out `'bob'`. The remaining strings `'ALICE'` and `'CAROL'` are passed to `n.lower()`, producing `'alice'` and `'carol'`.
Why does this comprehension result in a syntax error?
A filtering `if` clause must go after the `for` clause, not before it. Moving `if x > 1` to after `for x in nums` fixes the error: `[x * 2 for x in nums if x > 1]`.
A filtering `if` must go *after* the `for` clause (`[x * 2 for x in nums if x > 1]`). Putting it before the `for` is only valid when using an `if-else` ternary expression.
Practice tasks
Filter and extract usernames
The current code correctly filters for active users, but it only extracts their IDs. Modify the list comprehension so that it extracts the `username` (as a string) instead of the `id`.
Challenge
Transform database rows into API response dicts
You have a `list` of `dict`s representing database rows with keys `'id'`, `'email'`, `'role'`, and `'is_active'`. Using list comprehensions, produce a `list` of response `dict`s containing only `'id'` and `'email'` for users whose `'role'` is `'admin'` and who are active.
Continue learning
Previous: Lists: indexing, slicing, methods
Previous: for and while loops
Previous: if/elif/else and Python truthiness
Next: Dictionary and set comprehensions
Next: Nested comprehensions