Skip to content

Comprehensions

Comprehensions are a compact way to build new collections from existing data. They help you express a loop, an optional filter, and a transformation in a single expression when the logic stays simple.


Without a comprehension, you usually write a loop, an optional condition, and an append step.

result = []
for x in range(10):
if x % 2 == 0:
result.append(x**2)

The same idea in one line:

result = [x**2 for x in range(10) if x % 2 == 0]
  • A comprehension combines a loop, a filter, and a result expression
  • It removes repeated setup code
  • It works best when the transformation is easy to read at a glance

[expression for item in iterable if condition]
PartMeaning
expressionWhat to generate
itemCurrent element
iterableSource collection
conditionOptional filter

graph TD Start --> Loop["Take the next item"] Loop --> Condition{"Does it match the filter?"} Condition -->|Yes| Transform["Run the expression"] Transform --> Store["Add result to collection"] Store --> Loop Condition -->|No| Loop Loop --> End["Collection is complete"]

List comprehensions build a new list from an iterable.

squares = [x**2 for x in range(10)]
even_squares = [x**2 for x in range(10) if x % 2 == 0]
even_squares = []
for x in range(10):
if x % 2 == 0:
even_squares.append(x**2)
pairs = [(x, y) for x in range(2) for y in range(2)]
# Output: [(0, 0), (0, 1), (1, 0), (1, 1)]
labels = ["even" if x % 2 == 0 else "odd" for x in range(5)]

Set comprehensions build a set, so duplicate values are removed automatically.

unique_squares = {x**2 for x in range(10)}
  • Removing duplicate values
  • Building a quick lookup set
nums = [1, 2, 2, 3]
unique = {x for x in nums} # {1, 2, 3}

Dictionary comprehensions create key-value pairs from an iterable.

square_dict = {x: x**2 for x in range(5)}
filtered = {x: x**2 for x in range(10) if x % 2 == 0}
words = ["apple", "banana", "cherry"]
length_map = {word: len(word) for word in words}

Generator expressions use round brackets instead of square brackets. They produce values one by one instead of building the full result at once.

gen = (x**2 for x in range(10))
  • List comprehensions create the full list immediately
  • Generator expressions create items only when needed
for value in gen:
print(value)

graph TD List["List comprehension"] --> A["Stores every value at once"] Gen["Generator expression"] --> B["Produces one value at a time"]

  • A loop usually performs several repeated steps in Python
  • A comprehension keeps that pattern tighter and simpler for the interpreter
# loop style
result.append(x)
# comprehension style
[x for x in iterable]

The variable used inside a comprehension does not leak into the outer scope.


# Loop
result = []
for x in range(1000000):
result.append(x)
# Comprehension
result = [x for x in range(1000000)]

For simple transformations, the comprehension is usually shorter and often faster.


  • The logic is short and direct
  • You are transforming or filtering one iterable into another
  • The result fits naturally into a single expression
  • The logic has many branches
  • You need several nested conditions
  • A normal loop would be easier to read and debug

This is too crowded for a comprehension:

result = [x*y for x in range(10) for y in range(10) if x % 2 == 0 if y % 3 == 0]

The loop version is easier to scan:

result = []
for x in range(10):
if x % 2 != 0:
continue
for y in range(10):
if y % 3 == 0:
result.append(x*y)

x = 10
lst = [x for x in range(5)]
print(x) # 10

matrix = [[i*j for j in range(3)] for i in range(3)]
[
[0, 0, 0],
[0, 1, 2],
[0, 2, 4],
]

users = [{"active": True}, {"active": False}]
active_users = [u for u in users if u["active"]]
prices = [100, 200, 300]
discounted = [p * 0.9 for p in prices]
matrix = [[1, 2], [3, 4]]
flat = [num for row in matrix for num in row]