List Comprehensions in Python: A Complete Guide
Everything about list comprehensions in one place: how the syntax maps to a loop, where if and if-else go (and the SyntaxError when they are swapped), nested loops in the right order, dict and set comprehensions, generator expressions for large data, the walrus operator, and the point where a plain loop reads better.
GloryTecks Team
Training & Placement Faculty
Last updated: 24 September 2026
A list comprehension builds a new list from an existing iterable in a single expression. Once you can see the loop inside it, the syntax stops being clever and becomes simply compact. This guide starts from that loop, then covers the patterns people get wrong and the point where a comprehension should go back to being a loop.
The loop inside every comprehension
prices = [120, 80, 45, 300, 15]
with_tax = []
for p in prices:
if p >= 50:
with_tax.append(round(p * 1.18, 2))
same = [round(p * 1.18, 2) for p in prices if p >= 50]
print(with_tax == same, same)True [141.6, 94.4, 354.0]Read the comprehension as the loop with the append moved to the front: what to produce (round(p * 1.18, 2)), then where it comes from (for p in prices), then which items qualify (if p >= 50). The Python tutorial defines it the same way: an expression followed by a for clause, then zero or more for or if clauses (Python tutorial: list comprehensions).
if at the end filters; if-else at the front transforms
These two look alike and do different jobs:
readings = [12, -3, 7, -1]
print([r for r in readings if r > 0]) # filter: drops items
print([r if r > 0 else 0 for r in readings]) # transform: keeps every item[12, 7]
[12, 0, 7, 0]A trailing if decides whether an item is included, and it cannot have an else. A conditional expression (a if cond else b) is part of what to produce, so it goes at the front. Put the else at the end and Python refuses:
try:
compile("[r for r in readings if r > 0 else 0]", "<example>", "eval")
except SyntaxError as exc:
print(exc.msg)invalid syntaxNested loops: same order as the for statements
With two for clauses, the order is the order you would nest the loops, outer first:
matrix = [[1, 2, 3], [4, 5, 6]]
print([x for row in matrix for x in row])
print([(size, colour) for size in "SM" for colour in ("red", "blue")])[1, 2, 3, 4, 5, 6]
[('S', 'red'), ('S', 'blue'), ('M', 'red'), ('M', 'blue')]A comprehension placed inside the expression is different: it builds a list per outer item. That is how you transpose a matrix, although zip says it more directly:
print([[row[i] for row in matrix] for i in range(3)])
print([list(col) for col in zip(*matrix)])[[1, 4], [2, 5], [3, 6]]
[[1, 4], [2, 5], [3, 6]]Dict and set comprehensions
Swap the brackets for braces and you get a set; add key: value and you get a dictionary (Python reference: displays):
emails = ["Asha@Example.com", "ravi@example.com", "asha@example.com"]
print(sorted({e.lower() for e in emails}))
stock = {"pen": 40, "stapler": 0, "notebook": 12}
print({item: qty for item, qty in stock.items() if qty > 0})
print({qty: item for item, qty in stock.items()}) # inverted: values become keys['asha@example.com', 'ravi@example.com']
{'pen': 40, 'notebook': 12}
{40: 'pen', 0: 'stapler', 12: 'notebook'}The set removed the duplicate address after lower-casing; sorted() is there only because a set has no order, so printing it directly can list the items differently from run to run. When inverting a dictionary, duplicate values collapse: the last key with a given value wins.
Generator expressions for large data
Round brackets make a generator expression. It produces items one at a time instead of building the whole list, so memory stays flat however large the input (Python reference: generator expressions):
import sys
squares_list = [n * n for n in range(1_000_000)]
squares_gen = (n * n for n in range(1_000_000))
print(sys.getsizeof(squares_list), sys.getsizeof(squares_gen))
print(sum(n * n for n in range(1_000_000)) == sum(squares_list))8448728 208
TrueThe list's container alone takes about 8 MB (the integers it points to take more); the generator object is about 200 bytes whatever the range. When a generator expression is the only argument to a function, as in sum(...), the extra brackets can be dropped. If you only loop over the results once, especially feeding sum, max, any, all or "".join, prefer the generator. For how generators work underneath, see Python generators and iterators made simple.
Reusing a computed value with :=
Sometimes the filter needs the same computation as the output. The assignment expression (:=, Python 3.8+) computes it once (PEP 572):
raw = ["42", "n/a", "17", ""]
def parse(s):
return int(s) if s.isdigit() else None
print([n for s in raw if (n := parse(s)) is not None])[42, 17]Without it you would call parse(s) twice, once in the condition and once in the expression.
Scope: the loop variable stays inside
In Python 3, a comprehension runs in its own scope, so its loop variable does not overwrite a variable of the same name outside:
p = "unchanged"
_ = [p for p in prices]
print(p)unchanged(A plain for loop does leave its variable behind.) The same isolation applies to set and dict comprehensions and to generator expressions.
When to write a loop instead
A comprehension is for building a collection. Switch back to a loop when:
- You want side effects, such as printing, writing to a file or appending elsewhere.
[print(x) for x in items]builds a useless list ofNonevalues. - There are more than two for clauses, or the conditions need
and/orchains that do not fit on one readable line. - You need error handling per item. A
trycannot go inside a comprehension; move the logic into a function and call it, or use a loop.
Comprehensions are usually a little faster than the equivalent append loop, because the append happens inside the interpreter. The difference is rarely what matters; readability is. If speed does matter, measure both with timeit on your data.
A worked example: from messy input to clean data
Comprehensions shine when a cleaning job is a short sequence of steps, each producing a new collection. Suppose a form export gives you a list of city names typed by hand: stray spaces, mixed case, blanks and repeats. One comprehension strips and title-cases the entries while dropping blanks; a set comprehension removes duplicates; sorted puts the result in order. Each step is one readable line, and each intermediate result can be printed while you develop. When a step needs more than a transformation and a condition, for example looking up a correction table and logging unknown names, move that step into a small function and call it from the comprehension. The comprehension stays short and the logic gets a name and a test.
Are list comprehensions better than map and filter?
Can I use break inside a comprehension?
Is there a tuple comprehension?
How long is too long?
Comprehensions produce the core collection types; Python lists vs tuples vs sets vs dictionaries explains when each one fits. List comprehensions are taught in the data structures module of the Python Programming course, with comprehensions and generators revisited in its advanced concepts module.
Sources
- List Comprehensions (tutorial) — Python documentation
- Displays for lists, sets and dictionaries — Python documentation
- Generator expressions — Python documentation
- PEP 572 – Assignment Expressions — Python Enhancement Proposals
GloryTecks Team
Training & Placement Faculty
The GloryTecks faculty team mentors learners across Data Science, AI and Data Engineering, with a focus on real-time projects and placement readiness in Hyderabad.
Want to master Python?
Join GloryTecks’ expert-led Python Programming training in Hyderabad with real-time projects and 100% placement support.
Related articles
Learn Python from Scratch: A Complete 2026 Roadmap
How to learn Python from zero: install a current version (including the new Windows install manager), then work through seven stages, from values and loops to files, virtual environments, classes and tests, each ending with a small program you should be able to write on your own.
Python Interview Questions: Top 50 with Answers
Fifty conceptual Python interview questions with short, precise answers, grouped by topic: basics, types and mutability, data structures, functions and scope, OOP, iterators and decorators, errors and files, and internals, with runnable examples for the ones people most often get wrong.
Python for Data Science: The Essential Libraries
The Python data science stack explained by the job each library does: NumPy for arrays, pandas for tables, Matplotlib and seaborn for charts, SciPy and statsmodels for statistics, scikit-learn for models and Jupyter for exploration, with one runnable example that passes a real dataset through them.