Work with higher-order functions¶
The question. You want to transform a sequence, select items from it, or combine it into a single value by passing a little function around rather than writing a loop each time.
The four tools you'll use ninety percent of the time are map, filter, sorted(..., key=...), and functools.reduce. The first three are built-ins; reduce lives in functools. The single answer cell below covers the three you'll reach for most, plus a pipeline helper for when you want left-to-right data flow.
from functools import reduce
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# map: transform every item.
squared = list(map(lambda n: n ** 2, numbers))
print('squared: ', squared)
# filter: keep only items that satisfy a predicate.
evens = list(filter(lambda n: n % 2 == 0, numbers))
print('evens: ', evens)
# sorted with a key: sort dicts by a field, breaking ties with another.
students = [
{'name': 'Alice', 'grade': 85},
{'name': 'Bob', 'grade': 85},
{'name': 'Charlie', 'grade': 92},
]
ranked = sorted(students, key=lambda s: (-s['grade'], s['name']))
for s in ranked:
print(f" {s['name']}: {s['grade']}")
# reduce: when no built-in does the job. Here: product of a list.
product = reduce(lambda a, b: a * b, numbers)
print('product: ', product)
def pipeline(value, *steps):
"""Apply functions left to right. Reads like a recipe."""
for step in steps:
value = step(value)
return value
processed = pipeline(
[10.5, -3.0, 25.99, 0, 15.75],
lambda xs: [x for x in xs if x > 0], # drop non-positive
lambda xs: [x * 0.9 for x in xs], # 10% discount
lambda xs: [round(x, 2) for x in xs], # tidy
)
print('pipeline:', processed)
Why it works¶
map and filter return iterators, not lists. The list(...) calls above are only there to force evaluation so you can print the result. In a real pipeline you'd chain the next operation directly onto the iterator, and only materialise at the end — that's where the memory saving comes from.
sorted's key parameter accepts any callable that takes one item and returns something comparable. Returning a tuple lets you sort by multiple criteria — (-grade, name) sorts by grade descending (negating flips the order) and breaks ties by name ascending. Python compares tuples left to right, which is exactly what you want.
reduce(f, iterable) is "fold from the left" — it applies f to the first two items, then to the result and the third item, and so on. For sum use sum, for join use str.join, for max use max with a key — reach for reduce only when no built-in fits.
The pipeline helper is optional sugar. It's just a for loop that assigns back into value; the reason it earns a name is that the call site reads top-to-bottom in the order the operations happen, which is easier to hold in your head than round_all(discount(drop_negative(xs))).
Trade-offs and when a comprehension is better¶
- List comprehensions beat
map+filterfor readability in most cases.[n ** 2 for n in numbers if n % 2 == 0]is shorter and easier to follow thanlist(map(lambda n: n ** 2, filter(lambda n: n % 2 == 0, numbers))). - Reach for
map/filterwhen you already have a named function.list(map(str.upper, words))is genuinely nicer than[w.upper() for w in words]because it puts the operation first. - Generator expressions are
mapandfilterwith comprehension syntax.(n ** 2 for n in numbers if n % 2 == 0)is lazy, memory-friendly, and reads like Python. Use these when you want lazy evaluation but also want readable code. reduceis a last resort. Built-ins exist for sum, max, min, any, all, and string joining. Readers mentally parse those faster than they parsereduce(lambda a, b: ..., xs)— only drop back toreducewhen there's no built-in.- Pipelines shine for multi-step data processing. For simple one-step transformations, a single
mapor comprehension is clearer. The pipeline earns its keep only once there are three or more steps.
Related¶
- Learn — Lambda expressions for the one-liner functions passed to
map,filter, andsorted. - Guide — Iterators and generators for the deeper picture of why these return iterators.
- Reference — Built-in functions for
map,filter,sorted,sum,max,any,all. - Concepts — First-class functions in Python for why passing a function as an argument is nothing special.