How do list, dict, and set comprehensions work in Python, and when should you avoid them?
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
What the interviewer wants to hear
Beyond “it’s a shorter for loop”, a strong answer covers all three variants (list, dict, set), explains the speed win, mentions generator expressions as the memory-efficient cousin, and knows when not to use them.
Syntax and variants
The general form is [expression for item in iterable if condition]. The brackets change depending on the type you want:
# List comprehension — square brackets
squares = [x**2 for x in range(10) if x % 2 == 0]
# [0, 4, 16, 36, 64]
# Dict comprehension — curly braces with a colon
word_lengths = {word: len(word) for word in ["apple", "fig", "banana"]}
# {'apple': 5, 'fig': 3, 'banana': 6}
# Set comprehension — curly braces, no colon (deduplicates automatically)
domains = {email.split("@")[1] for email in ["a@x.com", "b@x.com", "c@y.com"]}
# {'x.com', 'y.com'}
# Generator expression — parentheses — lazy, O(1) memory
total = sum(x**2 for x in range(1_000_000))
Why they are faster than plain loops
A list comprehension uses a dedicated LIST_APPEND bytecode that runs at the C level. A plain for loop calling result.append(x) has to look up the append attribute on every iteration. The comprehension skips that lookup, giving a 20–50% speedup for typical workloads.
Interactive playground — all three comprehension types
Nested comprehension — read order matches loop order
# Flatten a 2-D list
flat = [val for row in matrix for val in row]
# This reads exactly like the nested loop:
for row in matrix:
for val in row:
flat.append(val)
When to use a plain loop instead
If the expression needs more than a quick glance to understand, reach for a loop:
# Too dense — hard to debug or extend later
result = [transform(x) for x in data if predicate(x) if secondary(x)]
# Clearer as a loop
result = []
for x in data:
if predicate(x) and secondary(x):
result.append(transform(x))