# Transform + filter
temps_f = [32, 68, 95, 104, 50]
warm_c = [(f - 32) * 5 / 9for f in temps_f if f > 60]
print([round(c, 1) for c in warm_c])
# Nested comprehension (flatten)
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [n for row in matrix for n in row]
print(flat)
output
[20.0, 35.0, 40.0]
[1, 2, 3, 4, 5, 6]
Note In nested comprehensions, the outer loop comes first: [x for row in matrix for x in row]. This matches the order of equivalent nested for loops.
list comprehensionflatten listnested comprehensionfilter and transform
Dict Comprehensions (Detailed)
syntax
{key_expr: val_expr for item in iterable if cond}
example
# Invert a dictionary
http_codes = {200: "OK", 404: "Not Found", 500: "Server Error"}
code_lookup = {msg: code for code, msg in http_codes.items()}
print(code_lookup["Not Found"])
# From two parallel lists
keys = ["host", "port", "debug"]
vals = ["localhost", 8080, True]
config = {k: v for k, v in zip(keys, vals)}
print(config)
Note When inverting a dict, duplicate values in the original will cause key collisions; the last one wins.
dict comprehensioninvert dictionaryzip to dictbuild dict
Set Comprehensions
syntax
{expr for item in iterable if cond}
example
sentence = "the quick brown fox jumps over the lazy dog"
word_lengths = {len(word) for word in sentence.split()}
print(sorted(word_lengths))
output
[3, 4, 5]
Note Set comprehensions look like dict comprehensions but without the colon. They automatically deduplicate results.
set comprehensionunique values comprehensiondeduplicate transform
Generator Expressions
syntax
(expr for item in iterable if cond)
example
# Sum of squares without building a list
total = sum(n ** 2for n in range(1, 101))
print(total)
# Lazy evaluationimport sys
list_size = sys.getsizeof([x for x in range(10000)])
gen_size = sys.getsizeof(x for x in range(10000))
print(f"List: {list_size} bytes, Generator: {gen_size} bytes")
output
338350
List: ~85000 bytes, Generator: ~200 bytes
Note Generator expressions use parentheses instead of brackets and are lazy — they produce values on demand. When passed as the sole argument to a function, extra parens can be omitted.
def flatten(nested):
for item in nested:
if isinstance(item, list):
yieldfrom flatten(item)
else:
yield item
data = [1, [2, [3, 4]], [5, 6]]
print(list(flatten(data)))
output
[1, 2, 3, 4, 5, 6]
Note yield from delegates to a sub-generator and passes values through. It handles send() and throw() transparently, unlike a manual for-loop with yield.
Note itertools functions return lazy iterators. They compose well and avoid creating intermediate lists. See also: accumulate, starmap, tee, zip_longest.
itertoolschainisliceproductgroupbycombinations
itertools.groupby
syntax
from itertools import groupby
for key, groupin groupby(iterable, key=func):
example
from itertools import groupby
transactions = [
{"type": "credit", "amount": 100},
{"type": "credit", "amount": 200},
{"type": "debit", "amount": 50},
{"type": "debit", "amount": 75},
]
# Must be sorted by the grouping key first!for ttype, groupin groupby(transactions, key=lambda t: t["type"]):
amounts = [t["amount"] for t ingroup]
print(f"{ttype}: {amounts}")
output
credit: [100, 200]
debit: [50, 75]
Note groupby only groups consecutive items with the same key. Sort the data by the key first, or you get fragmented groups.
groupbygroup itemscategorizecluster by key
Walrus Operator in Comprehensions
syntax
[y := f(x) ... if y > threshold]
example
import math
values = [1, 10, 100, 1000, 10000]
# Compute once, use in both filter and output
result = [
(v, log_v)
for v invaluesif (log_v := math.log10(v)) >= 2
]
print(result)
output
[(100, 2.0), (1000, 3.0), (10000, 4.0)]
Note The walrus operator avoids computing the same expression twice in a comprehension. The variable leaks into the enclosing scope, which can be surprising.
walrus comprehensionassignment in comprehensionavoid double computation