List and Dictionary Comprehensions
A comprehension creates a new collection by transforming and optionally filtering an iterable. It does not modify the source iterable.
List comprehensions
The expression comes first, followed by the for clause and then any filter.
numbers = range(1, 6)
squares = [number**2 for number in numbers]
print(squares) # [1, 4, 9, 16, 25]
Add an if clause to keep selected inputs:
numbers = range(1, 11)
even_squares = [number**2 for number in numbers if number % 2 == 0]
print(even_squares) # [4, 16, 36, 64, 100]
Multiple for clauses follow the same order as equivalent nested loops. This common pattern flattens one level of nesting:
matrix = [[1, 2, 3], [4, 5, 6]]
flattened = [value for row in matrix for value in row]
print(flattened) # [1, 2, 3, 4, 5, 6]
Dictionary comprehensions
A dictionary comprehension supplies both a key and a value expression.
words = ["data", "science", "python"]
lengths = {word: len(word) for word in words}
print(lengths) # {'data': 4, 'science': 7, 'python': 6}
If multiple inputs produce the same key, the later value replaces the earlier one, just as with ordinary dictionary assignment.
pairs = [("A", 1), ("B", 2), ("A", 3)]
latest = {key: value for key, value in pairs}
print(latest) # {'A': 3, 'B': 2}
Readability first
Comprehensions are best for a single clear transformation with a small filter. Use an ordinary loop when the work has side effects, needs several branches, or would require a deeply nested expression.
readings = [3.5, None, 4.0, -1.0]
valid_readings = [value for value in readings if value is not None and value >= 0]
print(valid_readings) # [3.5, 4.0]
Generator expressions use parentheses and produce values lazily. They are useful when a consuming function does not need a list:
total = sum(number**2 for number in range(5))
print(total) # 30