Skip to content

Python · Comprehensions & Iteration

Python Comprehensions Explained — List, Dict, Set, and When Not to Use Them

4 min read Updated 2026-06-19 Share:

Practice List, Dict & Set Comprehensions interview questions

Python comprehensions, explained

Comprehensions are one of the first things that make Python code look like Python. They build a collection from an iterable in a single readable expression — but they also get abused into write-only one-liners. This guide covers the variants and, just as importantly, when to stop.

The basic list comprehension

A list comprehension builds a list by transforming each item of an iterable:

squares = [x * x for x in range(5)]    # [0, 1, 4, 9, 16]

# equivalent loop:
squares = []
for x in range(5):
    squares.append(x * x)

It's both shorter and slightly faster than the loop, because the iteration and appending run in C. Read it as "give me x * x for each x in the range".

Filtering with a trailing if

Add an if at the end to keep only some items:

evens = [x for x in range(10) if x % 2 == 0]    # [0, 2, 4, 6, 8]

This if is a filter — items that fail are skipped entirely.

Conditional transform with a leading if/else

Don't confuse the filter if with a conditional expression. To choose between two values, the if/else goes before the for (it's a ternary on the output):

labels = ["even" if x % 2 == 0 else "odd" for x in range(4)]
# ['even', 'odd', 'even', 'odd']

Rule of thumb: if at the end filters; if/else at the front transforms.

Dict and set comprehensions

The same syntax builds dicts (with key: value) and sets (with {} and no colon):

squares = {x: x * x for x in range(4)}      # {0: 0, 1: 1, 2: 4, 3: 9}  — dict
unique = {x % 3 for x in range(10)}         # {0, 1, 2}                 — set

# invert a dict
prices = {"a": 1, "b": 2}
by_price = {v: k for k, v in prices.items()}   # {1: 'a', 2: 'b'}

Nested comprehensions

You can iterate multiple loops in one comprehension. The clauses read left to right, in the same order as nested for loops:

pairs = [(x, y) for x in range(2) for y in range(2)]
# [(0, 0), (0, 1), (1, 0), (1, 1)]

Flattening a list of lists is a common case:

matrix = [[1, 2], [3, 4]]
flat = [n for row in matrix for n in row]    # [1, 2, 3, 4]

A nested comprehension (a comprehension inside the output) builds nested structures:

grid = [[0 for _ in range(3)] for _ in range(2)]   # 2x3 grid

Note: build the grid this way, not with [[0] * 3] * 2, which shares the inner list across rows.

When NOT to use a comprehension

Comprehensions are for building a collection. Reach for a plain loop when:

  • You're acting for side effects (printing, writing to a file) — don't build a throwaway list just to loop.
  • The logic needs try/except, multiple statements, or several conditions — it stops being readable.
  • It would be deeply nested — two for clauses is usually the readability limit.
# Don't do this — comprehension used only for side effects:
[print(x) for x in items]      # builds a useless list of Nones

# Just loop:
for x in items:
    print(x)

Generator expressions for large data

If you only need to iterate once, a generator expression (parentheses instead of brackets) avoids building the whole list in memory:

total = sum(x * x for x in range(1_000_000))   # lazy — no giant list

Recap

A comprehension builds a collection from an iterable in one expression: a trailing iffilters, while a leading if/else transforms. The same syntax produces dicts ({k: v ...}) and sets ({x ...}), and multiple for clauses read left-to-right for nesting and flattening. Skip the comprehension when you're looping for side effects or when the logic gets complex — and use a parenthesised generator expression when the data is large and you only iterate once.

More ways to practice

The self-quiz is live. Get notified when mock interviews and new question packs drop.

or
Join our WhatsApp Channel