datarekha
Python Easy Asked at AmazonAsked at GoogleAsked at Meta

How do list, dict, and set comprehensions work in Python, and when should you avoid them?

The short answer

Comprehensions are syntactic sugar for building a new collection by iterating over an iterable and optionally filtering elements. They are faster than equivalent for-loops because the iteration runs at the C level inside the interpreter. Avoid them when the expression is too complex to read at a glance — a plain loop with descriptive variable names is preferable.

How to think about it

“It’s a shorter for loop” is the answer that earns a polite nod and a harder follow-up. A strong answer covers all three forms — list, dict, and set — explains why they run faster than a hand-written loop, knows the lazy generator-expression cousin, and, just as importantly, knows when a plain loop is the better call.

The shape is always the same: [expression for item in iterable if condition]. Only the brackets change to pick the container:

# List — square brackets
squares = [x**2 for x in range(10) if x % 2 == 0]
# [0, 4, 16, 36, 64]

# Dict — braces with a colon
word_lengths = {word: len(word) for word in ["apple", "fig", "banana"]}
# {'apple': 5, 'fig': 3, 'banana': 6}

# Set — braces, no colon (deduplicates for free)
domains = {email.split("@")[1] for email in ["a@x.com", "b@x.com", "c@y.com"]}
# {'x.com', 'y.com'}

# Generator — parentheses — lazy, O(1) memory
total = sum(x**2 for x in range(1_000_000))

Why they beat a plain loop

A list comprehension compiles to a dedicated LIST_APPEND bytecode that runs in C. A hand-written loop calling result.append(x) has to look up the append attribute on the list every single iteration; the comprehension skips that lookup entirely, which is where the typical 20–50% speedup comes from.

A worked example

# List comprehension with a filter
squares_of_evens = [x**2 for x in range(1, 11) if x % 2 == 0]
print("Squares of evens:", squares_of_evens)

# Dict comprehension — invert a mapping
original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
print("Inverted dict:", inverted)

# Set comprehension — unique first letters (sets dedupe automatically)
words = ["apple", "avocado", "banana", "blueberry", "cherry"]
first_letters = {w[0] for w in words}
print("First letters (set):", sorted(first_letters))

# Nested comprehension — flatten a 2-D list (loops read left to right)
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [val for row in matrix for val in row]
print("Flattened matrix:", flat)

# Dict comprehension — a word-frequency count
sentence = "the cat sat on the mat"
freq = {word: sentence.split().count(word) for word in sorted(set(sentence.split()))}
print("Word frequencies:", freq)
Squares of evens: [4, 16, 36, 64, 100]
Inverted dict: {1: 'a', 2: 'b', 3: 'c'}
First letters (set): ['a', 'b', 'c']
Flattened matrix: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Word frequencies: {'cat': 1, 'mat': 1, 'on': 1, 'sat': 1, 'the': 2}

The nested one is worth a second look. [val for row in matrix for val in row] reads in the same order as the loop it replaces — outer loop first, inner loop second:

for row in matrix:
    for val in row:
        flat.append(val)

When a plain loop wins

The moment a comprehension needs more than a glance to parse, reach for the loop — readability beats cleverness:

# Too dense to debug or extend
result = [transform(x) for x in data if predicate(x) if secondary(x)]

# Clearer, and far easier to step through
result = []
for x in data:
    if predicate(x) and secondary(x):
        result.append(transform(x))
Learn it properly Comprehensions

Keep practising

All Python questions

Explore further

Skip to content