Skip to main content

Lambdas and Small Callables

A lambda expression creates an anonymous function containing one expression:

by_last_name = lambda person: person.last_name.casefold()
people.sort(key=by_last_name)

Its best use is a short callable passed directly to an API, especially a key= argument. A named function is clearer when logic needs a docstring, type annotations, reuse, multiple steps, or meaningful error traces.

records.sort(key=lambda row: (row.priority, row.created_at))

Prefer comprehensions or generator expressions for ordinary transformation and filtering:

active_names = [user.name for user in users if user.active]
total = sum(order.amount for order in orders)

They usually communicate intent better than nesting map, filter, and lambdas. map remains useful when an existing named callable already expresses the operation.

Closure boundary​

Functions close over names, whose values are looked up when the function runs. Creating callbacks in a loop therefore has a late-binding trap:

callbacks = [lambda: index for index in range(3)]
# Every callback returns 2.

Capture the current value explicitly when that is the desired contract:

callbacks = [lambda index=index: index for index in range(3)]

The default argument is evaluated while each function is created. For larger callbacks, a small factory function or functools.partial is easier to explain.

Do not treat lambda syntax as a signal for functional purity. A lambda can call stateful functions and mutate objects just like a named function.

Source​

Explore connectionsOpen network