HomeGuidesPythonPython List Comprehensions Explained — Syntax & Performance
🐍 Python

Python List Comprehensions: Syntax, Filtering & Exam Traps

A concise way to create lists — and a favourite topic on Python exams. Learn the syntax, filtering, nesting, and the generator expression gotcha.

Examifyr·2026·5 min read

Basic syntax

A list comprehension creates a new list by applying an expression to each item in an iterable. The general form is `[expression for item in iterable]`.

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

words = ['hello', 'world']
upper = [w.upper() for w in words]
print(upper)  # ['HELLO', 'WORLD']
Note: List comprehensions always return a new list — the original iterable is not modified.

Filtering with if

Add an `if` clause after the iterable to keep only items that satisfy a condition.

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

# Combined: transform + filter
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares)  # [0, 4, 16, 36, 64]

Nested comprehensions

You can nest comprehensions to flatten or combine iterables. Read left-to-right like nested for loops.

matrix = [[1, 2], [3, 4], [5, 6]]

# Flatten a 2D list
flat = [x for row in matrix for x in row]
print(flat)  # [1, 2, 3, 4, 5, 6]

# 3×3 multiplication table
table = [[r * c for c in range(1, 4)] for r in range(1, 4)]
Note: The order is: outer loop first, inner loop second — same as nested for loops.

List comprehension vs loop — performance

List comprehensions are faster than equivalent for-loops because they are optimised at the C level in CPython. But clarity matters more than speed for small lists.

# Loop — slower, more verbose
result = []
for x in range(1000):
    result.append(x * 2)

# Comprehension — faster, one line
result = [x * 2 for x in range(1000)]

Generator expressions — the look-alike

Replace `[]` with `()` and you get a generator expression instead of a list. Generators are lazy — they produce values one at a time and use far less memory.

# List comprehension — creates the full list immediately
lst = [x**2 for x in range(1_000_000)]   # ~8 MB in memory

# Generator expression — produces values on demand
gen = (x**2 for x in range(1_000_000))   # almost no memory

print(next(gen))  # 0
print(next(gen))  # 1
Note: Exams often ask: "what is the difference between [x for x in …] and (x for x in …)?" — the answer is list vs generator (lazy evaluation).

Exam tip

The most common exam question is the list-vs-generator trap: `[x for x in range(5)]` returns a list, `(x for x in range(5))` returns a generator. Also watch for the filter-position gotcha — the `if` clause goes after the iterable, not after the expression.

🎯

Think you're ready? Prove it.

Take the free Python readiness test. Get a score, topic breakdown, and your exact weak areas.

Take the free Python test →

Free · No sign-up · Instant results

← Previous
Python File I/O Explained — open(), read, write & Context Managers
Next →
Python Decorators Explained — @syntax, functools.wraps & Stacking
← All Python guides