Python List and Dict Comprehensions: Syntax and Examples

Published Updated

A Python comprehension builds a list, dictionary, or set from an iterable in one expression. Use one to transform values or keep only the items you need. If loops are still new to you, start with the Python learning guide.

squares = [n * n for n in range(6)]

print(squares)
# Program output:
# [0, 1, 4, 9, 16, 25]

How Do Python Comprehensions Work?

A Python comprehension evaluates an expression for each item in an iterable, optionally skipping items with an if filter. The squares example above does the same work as this loop:

squares = []
for n in range(6):
    squares.append(n * n)

The List Form

The list form is written in square brackets and has three parts, read left to right:

# [ expression   for item in iterable   if condition ]
#   what to keep   where it comes from   which ones survive

The expression is evaluated once for each item that passes any filters, and its result goes into the new list. The for clause names the loop variable and the iterable it walks. The if clause is optional and decides which items reach the expression at all.

names = ["  Ada ", "bo", " Cleo"]

cleaned = [name.strip().title() for name in names]

print(cleaned)
# Program output:
# ['Ada', 'Bo', 'Cleo']

The source can be any iterable, not only a list. Strings, ranges, files, and dictionary views all work, and the result is always a new list rather than a change to the source.

The Dict Form

The dict form swaps the square brackets for braces and the single expression for a key and value separated by a colon:

# { key_expression: value_expression   for item in iterable   if condition }
words = ["apple", "fig", "banana"]

lengths = {word: len(word) for word in words}

print(lengths)
# Program output:
# {'apple': 5, 'fig': 3, 'banana': 6}

Feeding it .items() is how you transform a dictionary you already have. Unpacking the pair into two names keeps the body readable:

prices = {"apple": 1.5, "fig": 3.0}

doubled = {name: price * 2 for name, price in prices.items()}
inverted = {price: name for name, price in prices.items()}

print(doubled)
print(inverted)
# Program output:
# {'apple': 3.0, 'fig': 6.0}
# {1.5: 'apple', 3.0: 'fig'}

If you are unsure which result type you need, compare Python lists, dictionaries, and sets. A lossless inversion requires the values to be hashable and distinct. Repeated values still run, and they collapse, which is the collision pitfall below.

How Do You Filter a Python Comprehension?

A Python comprehension filters items with an if condition after the for clause. Items that fail it never reach the expression and never appear in the result:

scores = [85, 42, 91, 67, 95]

passing = [score for score in scores if score >= 70]

print(passing)
# Program output:
# [85, 91, 95]

The same clause works in the dict form, and it can test either half of the pair:

scores = {"Ada": 91, "Bo": 67, "Cleo": 85}

top = {name: score for name, score in scores.items() if score >= 85}

print(top)
# Program output:
# {'Ada': 91, 'Cleo': 85}

Where Does if-else Go in a Python Comprehension?

In a Python comprehension, if-else goes before the for clause. It chooses a value for each item rather than removing items:

scores = [85, 42, 91]

labels = ["pass" if score >= 70 else "fail" for score in scores]

print(labels)
# Program output:
# ['pass', 'fail', 'pass']

The position tells you which one you are reading. A bare if at the end drops items, and an if-else at the front keeps every item and changes what is stored. Both can appear in one comprehension, though that is usually the point to switch to a loop.

How Do Nested Python Comprehensions Work?

Nested Python comprehensions follow the same order as nested loops. With two for clauses, the outer loop comes first:

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

flat = [value for row in matrix for value in row]

print(flat)
# Program output:
# [1, 2, 3, 4, 5, 6]

Building a nested structure is the other direction, and there the inner comprehension sits inside the expression:

grid = [[row * 3 + col for col in range(3)] for row in range(2)]

print(grid)
# Program output:
# [[0, 1, 2], [3, 4, 5]]

In the matrix example, the two for clauses produce one flat list. In the grid example, the inner comprehension builds a separate list for each row. If you need to trace several nested loops to understand the result, use a plain loop or a named helper function.

When Should You Use a Loop Instead of a Comprehension?

Use a regular Python loop instead of a comprehension when you need several steps, per-item error handling, or actions such as writing files. A comprehension works best when the result is easy to read in one pass.

  • Two collections at once. One comprehension produces one result, so splitting items into passes and failures needs either two comprehensions over the same data or one loop.
  • Branching logic. A chain of conditions choosing between several values is usually easier to read in an if-elif-else block than in nested conditional expressions.
  • Error handling. The syntax has no room for try, so catching an error for each item needs a loop or a helper function.
  • Side effects. Printing, writing files, and calling an API are not what a comprehension is for, and using one that way builds a list of unused return values, often None.
  • Length. Breaking a comprehension across lines is fine. Switch to a loop when extra formatting still leaves the logic hard to follow.

The working rule is that a reader should get the result from one pass over the line. If they have to trace it, write the loop.

Pitfalls and Debugging

A Comprehension Used for Its Side Effect

Writing [print(x) for x in items] prints, and it also builds and discards a list of None values. Nothing raises, so the cost is invisible until the iterable is large:

items = ["a", "b"]

wasted = [print(item) for item in items]
print(wasted)
# Program output:
# a
# b
# [None, None]

The rule is that a comprehension is for producing a value. When you are not keeping the result, write for item in items: instead.

The Filter and the Value Swapped

Putting a bare if where an if-else belongs is a syntax error, which is the friendly version of this mistake:

# SyntaxError: expected 'else' after 'if' expression
# labels = [ "pass" if score >= 70 for score in scores ]

Putting an if-else after the for clause is also invalid syntax. To keep only passing scores, use [score for score in scores if score >= 70]. To label every score, put "pass" if score >= 70 else "fail" before the for clause.

Keys That Collide

A dict comprehension whose key expression repeats keeps the last pair silently, because that is what assigning to an existing key does:

people = [("admin", "Ada"), ("user", "Bo"), ("admin", "Cleo")]

by_role = {role: name for role, name in people}

print(by_role)
# Program output:
# {'admin': 'Cleo', 'user': 'Bo'}

Ada is gone and nothing said so. When keys can repeat, the data wanted a grouping loop that appends to a list per key, not a comprehension that stores one value per key.

Frequently Asked Questions

Are Python comprehensions faster than loops?

Python list comprehensions can be faster than equivalent loops that repeatedly call append(), but the difference depends on the Python version and the work each item requires. Choose the clearer form first and measure it if performance becomes a problem.

Can a Python comprehension use try and except?

A Python comprehension cannot contain try and except statements. Handle errors in a regular loop or in a helper function called by the comprehension.

Does a Python comprehension overwrite an outer loop variable?

A Python 3 comprehension does not overwrite an outer variable with its loop variable. The loop variable belongs to the comprehension, so an existing variable with the same name keeps its value.

How does a Python set comprehension work?

A Python set comprehension uses braces around an expression and a for clause, such as {word.lower() for word in words}. It keeps only unique results, and every result must be hashable.

How do you write a Python comprehension over two lists?

Use zip() in a Python comprehension to pair items from two lists by position. By default, zip() stops at the shorter list, so check the lengths if every item must be paired. Use two for clauses instead when you want every combination of items.

What is a Python generator expression?

A Python generator expression produces values on demand instead of building a whole collection. It uses parentheses, as in (n * n for n in range(6)), and works well when a function such as sum() consumes the values once.

Sources

  1. [1]
  2. [2]