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

6 May 2026 7 min read

Last updated: 24 September 2026

Share:

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

python
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)
text
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:

python
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
text
[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:

python
try:
    compile("[r for r in readings if r > 0 else 0]", "<example>", "eval")
except SyntaxError as exc:
    print(exc.msg)
text
invalid syntax

Nested loops: same order as the for statements

With two for clauses, the order is the order you would nest the loops, outer first:

python
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")])
text
[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:

python
print([[row[i] for row in matrix] for i in range(3)])
print([list(col) for col in zip(*matrix)])
text
[[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):

python
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
text
['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):

python
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))
text
8448728 208
True

The 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):

python
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])
text
[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:

python
p = "unchanged"
_ = [p for p in prices]
print(p)
text
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 of None values.
  • There are more than two for clauses, or the conditions need and/or chains that do not fit on one readable line.
  • You need error handling per item. A try cannot 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?

For expressions, usually yes: they read left to right and need no lambda. map is neat when you already have a named function, such as map(str.strip, lines). The lambda, map, filter and reduce guide compares them.

Can I use break inside a comprehension?

No. A comprehension always runs to the end of its input. To stop at the first match, use next() on a generator expression, such as next((o for o in orders if o.overdue), None), or itertools.takewhile to stop when a condition first fails.

Is there a tuple comprehension?

No. Round brackets make a generator expression. Wrap one in tuple(...) to build a tuple.

How long is too long?

If it does not fit comfortably on one or two lines, or a reader has to pause to work out the order of the clauses, use a loop.

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

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.

Explore course