What Are List Comprehensions?

List comprehensions are one of Python's most distinctive and powerful features. They let you create lists using a compact, readable expression — replacing multi-line for loops with a single, expressive line. Once you get comfortable with them, you'll find yourself reaching for them constantly.

Basic Syntax

The general form of a list comprehension is:

[expression for item in iterable]

Compare the two approaches below:

# Traditional loop
squares = []
for n in range(10):
    squares.append(n ** 2)

# List comprehension
squares = [n ** 2 for n in range(10)]

Both produce [0, 1, 4, 9, 16, 25, 36, 49, 64, 81], but the comprehension is more concise and — once you read it fluently — clearer in intent.

Adding Conditions (Filtering)

You can add an optional if clause to filter items:

# Only even squares
even_squares = [n ** 2 for n in range(10) if n % 2 == 0]
# → [0, 4, 16, 36, 64]

This replaces a loop with both an append and an if statement, cutting boilerplate in half.

Nested List Comprehensions

You can nest comprehensions to work with multi-dimensional data:

# Flatten a 2D matrix
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [val for row in matrix for val in row]
# → [1, 2, 3, 4, 5, 6, 7, 8, 9]

Read nested comprehensions left to right — the outer loop comes first, the inner loop second, just as they would in a traditional nested for loop.

Dictionary and Set Comprehensions

The same pattern extends to other data structures:

# Dictionary comprehension
word_lengths = {word: len(word) for word in ["hello", "world", "python"]}
# → {'hello': 5, 'world': 5, 'python': 6}

# Set comprehension (removes duplicates automatically)
unique_remainders = {n % 5 for n in range(20)}

When to Use Them — and When Not To

  • Use comprehensions when the logic is simple and the intent is clear at a glance.
  • Avoid comprehensions when the expression becomes long or requires multiple nested conditions — readability suffers fast.
  • Never use them for side effects. If your loop body calls a function for its side effect (printing, writing to a file), a regular for loop is more honest about intent.

Performance Considerations

List comprehensions are generally faster than equivalent for loops in CPython because the list-building machinery runs closer to C-speed. However, if you only need to iterate (not store) the result, a generator expression is more memory-efficient:

# Generator — doesn't build the list in memory
total = sum(n ** 2 for n in range(1_000_000))

Quick Reference

PatternSyntax
Basic[expr for x in iterable]
Filtered[expr for x in iterable if cond]
Nested[expr for x in a for y in b]
Dict{k: v for k, v in pairs}
Set{expr for x in iterable}
Generator(expr for x in iterable)

Conclusion

List comprehensions are a hallmark of idiomatic Python. Start with simple cases, keep expressions readable, and gradually tackle filtered and nested forms. Your code will become more expressive — and often faster — as a result.