Lambdas & Higher-Order Functions

A higher-order function takes other functions as arguments or returns one. Python's built-ins sorted, min, max, map and filter all work this way, and lambda lets you write the small functions they need right where you use them.

Lambda expressions

PY lambda.py
square = lambda n: n * n
add = lambda a, b: a + b

print(square(6), add(2, 3))

def square_def(n):
    return n * n

print(square_def(6))
Output
36 5
36

lambda params: expression creates a small anonymous function whose body is a single expression, automatically returned. Assigning a lambda to a name, as on the first line, is discouraged by style guides — use def for named functions. Lambdas shine as arguments.

Sorting with key

PY sort_key.py
people = [("Ana", 31), ("Ben", 25), ("Cleo", 31), ("Dev", 19)]

print(sorted(people, key=lambda p: p[1]))
print(sorted(people, key=lambda p: (-p[1], p[0])))
print(max(people, key=lambda p: p[1]))
print(min(["banana", "kiwi", "apple"], key=len))
Output
[('Dev', 19), ('Ben', 25), ('Ana', 31), ('Cleo', 31)]
[('Ana', 31), ('Cleo', 31), ('Ben', 25), ('Dev', 19)]
('Ana', 31)
kiwi

The key function is called once per item to produce the value that's compared. Returning a tuple sorts by several criteria; negating a number reverses that one criterion.

map and filter

PY map_filter.py
prices = [12.5, 7.0, 30.0, 4.25]

with_tax = list(map(lambda p: round(p * 1.2, 2), prices))
cheap = list(filter(lambda p: p < 10, prices))
as_text = list(map(str, prices))

print(with_tax)
print(cheap)
print(as_text)
Output
[15.0, 8.4, 36.0, 5.1]
[7.0, 4.25]
['12.5', '7.0', '30.0', '4.25']

map(fn, items) applies a function to each item; filter(fn, items) keeps items where it returns truthy. Both return lazy iterators, so wrap them in list() to see the results. In most Python code, comprehensions are preferred because they read more naturally:

PY comprehension_instead.py
prices = [12.5, 7.0, 30.0, 4.25]
print([round(p * 1.2, 2) for p in prices])
print([p for p in prices if p < 10])
Output
[15.0, 8.4, 36.0, 5.1]
[7.0, 4.25]

map remains neat when you already have a named function: map(str, numbers), map(int, line.split()).

Functions that return functions

PY factories.py
def multiplier(factor):
    return lambda n: n * factor

def greater_than(limit):
    def test(n):
        return n > limit
    return test

double = multiplier(2)
over_ten = greater_than(10)

print(double(21))
print(list(filter(over_ten, [5, 12, 9, 30])))
Output
42
[12, 30]

Each returned function is a closure, remembering the factor or limit it was created with.

functools helpers

PY functools_demo.py
from functools import partial, reduce
from operator import mul, itemgetter, attrgetter

power_of_two = partial(pow, 2)
print(power_of_two(10))

print(reduce(mul, [1, 2, 3, 4, 5]))

rows = [{"name": "Ana", "score": 91}, {"name": "Ben", "score": 78}]
print(sorted(rows, key=itemgetter("score")))

print(sorted(["b", "A", "c"], key=str.lower))
Output
1024
120
[{'name': 'Ben', 'score': 78}, {'name': 'Ana', 'score': 91}]
['A', 'b', 'c']
  • partial creates a new function with some arguments pre-filled.
  • reduce combines items pairwise into a single value. (Built-ins like sum, max and math.prod are usually clearer.)
  • operator.itemgetter and attrgetter are fast, readable replacements for lambdas like lambda d: d["score"].

Lesson 51 explores functools and itertools further.

Callbacks

Passing a function to be called later is the "callback" pattern, used in GUIs, web frameworks and event systems:

PY callbacks.py
def process(items, on_item, on_done):
    for item in items:
        on_item(item)
    on_done(len(items))

process(
    ["a.txt", "b.txt"],
    on_item=lambda name: print("processing", name),
    on_done=lambda n: print(f"finished {n} files"),
)
Output
processing a.txt
processing b.txt
finished 2 files

Lambda limitations

  • Only one expression — no statements, loops, try blocks or assignments (except :=).
  • No name in tracebacks: errors show <lambda>, which is harder to debug.
  • If a lambda gets long or is used in more than one place, turn it into a def.

Try it yourself

Try it yourself
Console output