Python List Comprehensions: The Complete Guide for 2026

Published February 15, 2026 · 20 min read

List comprehensions are one of Python’s most loved features: a compact way to build lists by transforming and filtering data. They can replace many small loops, make intent obvious, and often run faster than equivalent for loops.

In this guide you will learn the syntax, common patterns, and when not to use comprehensions. We’ll also cover dict/set comprehensions and generator expressions so you can choose the best tool for the job.

⚙ Related: For everyday Python reference, bookmark Python Basics Cheat Sheet and Pandas Cheat Sheet. If you are working with JSON data, try the JSON Formatter.

Table of Contents

  1. Syntax and mental model
  2. Transforming items
  3. Filtering with if
  4. Inline if/else vs filter
  5. Nested comprehensions
  6. Dict and set comprehensions
  7. Generator expressions
  8. Readability and performance
  9. Real-world examples
  10. FAQ

1. Syntax and mental model

The core structure is:

[expression for item in iterable]

Optionally add a filter:

[expression for item in iterable if condition]

You can translate a comprehension into a loop like this:

List comprehensionEquivalent loop
[f(x) for x in xs]
out = []
for x in xs:
    out.append(f(x))

2. Transforming items

Any expression is allowed on the left side: function calls, attribute access, arithmetic, string formatting.

# Uppercase all names
names = [name.upper() for name in ['alice', 'bob']]

# Extract a field from dicts
ids = [row['id'] for row in rows]

# Compute derived values
areas = [r * r * 3.14159 for r in radii]

3. Filtering with if

The trailing if acts as a filter. Items that do not match are omitted entirely.

# Keep only even numbers
evens = [x for x in nums if x % 2 == 0]

# Keep only non-empty strings
non_empty = [s for s in strings if s]

# Keep only files with a certain extension
py_files = [p for p in paths if p.endswith('.py')]

4. Inline if/else vs filter

There are two different “ifs” you can use:

# Filter: keep only positive numbers
positives = [x for x in nums if x > 0]

# Conditional expression: keep all numbers, but replace negatives with 0
clamped = [x if x > 0 else 0 for x in nums]
Common mistake: putting the if in the wrong place. The else belongs to the expression, not the filter.

5. Nested comprehensions

You can nest loops in a comprehension. The order matches normal Python loop nesting.

# Flatten a 2D list
flat = [x for row in matrix for x in row]

# Create pairs (cartesian product)
pairs = [(x, y) for x in xs for y in ys]

# Nested with filter
coords = [(r, c) for r in range(rows) for c in range(cols) if grid[r][c] == '#']
Tip: If a nested comprehension takes more than one line or has multiple conditions, consider a regular loop for readability.

6. Dict and set comprehensions

The same idea works for dicts and sets:

# Dict comprehension
by_id = {row['id']: row for row in rows}

# Set comprehension (unique values)
domains = {email.split('@')[1] for email in emails}

7. Generator expressions

A generator expression looks like a list comprehension but uses parentheses. It produces items lazily.

# List (eager)
squares_list = [x*x for x in range(10_000_000)]

# Generator (lazy)
squares_gen = (x*x for x in range(10_000_000))

# Consume lazily
total = sum(x*x for x in range(1_000_000))

8. Readability and performance

Some practical guidelines:

GoalBest tool
Build a small listList comprehension
Build a dict by keyDict comprehension
Unique valuesSet comprehension
Stream values into sum/any/allGenerator expression
Complex logic / multiple statementsFor loop

9. Real-world examples

Parse and normalize data

# Trim whitespace and drop empties
clean = [s.strip() for s in lines if s.strip()]

Extract nested fields from JSON-like data

# Keep only users with an email
emails = [u['email'].lower() for u in users if u.get('email')]

Convert types safely

def to_int(s):
    try:
        return int(s)
    except ValueError:
        return None

ints = [x for x in (to_int(s) for s in strings) if x is not None]

FAQ

Why does my list comprehension return a list of None?

This usually happens when you call a function that returns None (like list.sort()) or you use a comprehension for side effects. Use a loop for side effects, or return a value from your function.

Can I use async/await in a comprehension?

You can use comprehensions inside async functions, but you cannot await directly inside the expression in older Python versions. Prefer explicit loops or gather patterns when doing async I/O.

Related Resources

Python String Formatting Guide
Master f-strings and the format spec mini-language
Python Type Hints Guide
Write clearer code with typing, generics, and protocols
Python asyncio Guide
Concurrency patterns, tasks, cancellation, and debugging
Python Basics Cheat Sheet
Quick reference for syntax and common patterns
JSON Formatter
Format and validate JSON while working with APIs