Skip to content

Comprehensions Explained

A comprehension is a one-line way to build a list, dictionary, or set from another sequence. Instead of writing a loop that appends to a list, you describe what you want in a single expression. Comprehensions are one of Python's most distinctive features.

Learn Your Way

Read Build Watch Test Review Visualize
You are here Projects Videos Quiz Flashcards Diagrams

Why This Matters

Comprehensions make your code shorter, faster, and more readable — once you learn the pattern. They show up everywhere in Python: filtering data, transforming lists, building dictionaries from pairs, and more. Understanding them is essential from Level 2 onward.

Visualize It

Watch a list comprehension build a new list, step by step: Open in Python Tutor

List comprehensions

The most common type. Creates a new list by transforming each item:

# Without comprehension:
squares = []
for n in range(1, 6):
    squares.append(n ** 2)

# With comprehension — same result:
squares = [n ** 2 for n in range(1, 6)]
# [1, 4, 9, 16, 25]

The pattern is: [expression for variable in iterable]

Read it as: "give me expression for each variable in iterable."

Filtering with if

Add a condition to include only certain items:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Only even numbers:
evens = [n for n in numbers if n % 2 == 0]
# [2, 4, 6, 8, 10]

# Only words longer than 3 letters:
words = ["cat", "elephant", "dog", "hippopotamus"]
long_words = [w for w in words if len(w) > 3]
# ["elephant", "hippopotamus"]

The pattern is: [expression for variable in iterable if condition]

Transforming and filtering together

# Get uppercase versions of long words:
words = ["cat", "elephant", "dog", "hippopotamus"]
result = [w.upper() for w in words if len(w) > 3]
# ["ELEPHANT", "HIPPOPOTAMUS"]

The filter (if) decides which items to include. The expression (w.upper()) decides what to produce.

Dictionary comprehensions

Build a dictionary with {key: value for ...}:

# Square each number, store as {number: square}
squares = {n: n ** 2 for n in range(1, 6)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Flip a dictionary's keys and values:
original = {"a": 1, "b": 2, "c": 3}
flipped = {v: k for k, v in original.items()}
# {1: "a", 2: "b", 3: "c"}

# Filter a dictionary:
scores = {"Alice": 92, "Bob": 67, "Charlie": 85, "Diana": 58}
passing = {name: score for name, score in scores.items() if score >= 70}
# {"Alice": 92, "Charlie": 85}

Set comprehensions

Build a set (unique values only) with {expression for ...}:

words = ["hello", "HELLO", "Hello", "world", "WORLD"]
unique_lower = {w.lower() for w in words}
# {"hello", "world"}

Note: sets use {} just like dicts, but without the :. If there is no colon, Python knows it is a set.

Generator expressions

Use () instead of [] to create a generator instead of a list. Generators compute values lazily — one at a time — and use almost no memory:

# List comprehension — builds the whole list:
squares_list = [n ** 2 for n in range(1_000_000)]    # Uses ~8 MB

# Generator expression — computes on demand:
squares_gen = (n ** 2 for n in range(1_000_000))      # Uses ~100 bytes

# Pass directly to functions:
total = sum(n ** 2 for n in range(1_000_000))

See Generators and Iterators for a deeper dive.

Nested comprehensions

You can nest loops in a comprehension. The order matches the order you would write them as regular loops:

# Flatten a list of lists:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

# Equivalent loop:
flat = []
for row in matrix:
    for num in row:
        flat.append(num)

For creating a matrix:

# 3x3 grid of zeros:
grid = [[0 for col in range(3)] for row in range(3)]
# [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

Conditional expressions (if/else in the expression)

You can use if/else in the expression part (not the filter):

numbers = [1, 2, 3, 4, 5]

# "even" or "odd" label for each number:
labels = ["even" if n % 2 == 0 else "odd" for n in numbers]
# ["odd", "even", "odd", "even", "odd"]

Note the position: - Filter (which items): [x for x in items if condition]if at the end - Transform (what value): [a if condition else b for x in items]if/else before for

The walrus operator := in comprehensions

The walrus operator (:=, introduced in Python 3.8) lets you assign and use a value in the same expression. This avoids computing the same thing twice:

# Without walrus — calls len() twice:
data = ["hi", "hello", "hey", "howdy", "h"]
result = [(w, len(w)) for w in data if len(w) > 2]

# With walrus — calls len() once:
result = [(w, length) for w in data if (length := len(w)) > 2]
# [("hello", 5), ("hey", 3), ("howdy", 5)]

Another example — filtering and transforming expensive function calls:

import math

values = [1, -2, 3, -4, 5, 0]
# Only include values where the computation succeeds and is positive:
results = [
    y
    for x in values
    if (y := math.sqrt(abs(x))) > 1
]
# [1.414..., 1.732..., 2.0, 2.236...]

When to use comprehensions vs loops

Use a comprehension when: - You are building a new list/dict/set from an existing sequence - The logic is simple (one transform, one or two filters) - The result fits on one line (or two with good formatting)

Use a regular loop when: - You need side effects (printing, writing files, modifying other data) - The logic is complex (multiple conditions, nested transforms) - Readability suffers — if you have to squint to understand it, use a loop

# GOOD — simple and clear:
names = [user.name for user in users if user.is_active]

# BAD — too complex for a comprehension:
result = [
    transform(x, y)
    for x in items
    if validate(x)
    for y in x.children
    if y.status == "ready" and y.score > threshold
]
# Use a loop instead — your future self will thank you.

Common Mistakes

Confusing filter if with conditional expression if/else:

# Filter — decides WHICH items (if at end):
[x for x in range(10) if x > 5]          # [6, 7, 8, 9]

# Transform — decides WHAT value (if/else before for):
[x if x > 5 else 0 for x in range(10)]   # [0, 0, 0, 0, 0, 0, 6, 7, 8, 9]

# WRONG — if/else at end:
[x if x > 5 for x in range(10)]           # SyntaxError!

Forgetting that dict/set use {} but empty {} is a dict:

empty_dict = {}      # This is a dict, not a set
empty_set = set()    # Use set() for an empty set

Overusing comprehensions:

# This is not a comprehension — it is abuse:
[print(x) for x in range(10)]    # Works but creates a useless list of Nones
# Just use a for loop for side effects

Practice

Quick check: Take the quiz (coming soon)

Review: Flashcard decks Practice reps: Coding challenges

Further Reading


← Prev Home Next →