FunctionsChapter 55 of 114
Lambda
A small unnamed function, and when a def is the better choice.
A function in an expression
lambda builds a function without giving it a name:
double = lambda n: n * 2
print(double(5))Output
10
That is exactly equivalent to:
def double(n):
return n * 2
print(double(5))Output
10
Where it belongs
A lambda earns its place as an argument to something else, where naming it would be noise:
people = [("Ada", 36), ("Grace", 45), ("Katherine", 28)]
print(sorted(people, key=lambda person: person[1]))Output
[('Katherine', 28), ('Ada', 36), ('Grace', 45)]The function is used once, right there, and a name would not add anything.
words = ["banana", "Apple", "cherry"]
print(sorted(words, key=lambda w: w.lower()))
print(max(words, key=len))Output
['Apple', 'banana', 'cherry'] banana
The rules
A lambda takes any arguments but its body must be a single expression, whose value is returned automatically:
add = lambda a, b: a + b
greet = lambda name="there": f"Hello, {name}"
print(add(2, 3))
print(greet())
print(greet("Ada"))Output
5 Hello, there Hello, Ada
No statements are allowed — no if blocks, no loops, no assignments, no return. A conditional expression is fine, because it is an expression:
label = lambda n: "even" if n % 2 == 0 else "odd"
print(label(4), label(7))Output
even odd
With map and filter
numbers = [1, 2, 3, 4]
print(list(map(lambda n: n * n, numbers)))
print(list(filter(lambda n: n % 2 == 0, numbers)))Output
[1, 4, 9, 16] [2, 4]
Most Python programmers write those as comprehensions, which read left to right and need no lambda at all:
numbers = [1, 2, 3, 4]
print([n * n for n in numbers])
print([n for n in numbers if n % 2 == 0])Output
[1, 4, 9, 16] [2, 4]
The late-binding trap
A lambda looks up its enclosing variables when it runs, not when it is made. In a loop, that means every lambda sees the final value:
funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])Output
[2, 2, 2]
Capture the value with a default argument, which is evaluated at definition time:
funcs = [lambda i=i: i for i in range(3)]
print([f() for f in funcs])Output
[0, 1, 2]
This is not really about lambdas — a nested def behaves the same way — but this is where people meet it.
operator instead
For the common "get item n" or "add these" cases, operator is clearer than a lambda:
from operator import itemgetter
people = [("Ada", 36), ("Grace", 45)]
print(sorted(people, key=itemgetter(1), reverse=True))Output
[('Grace', 45), ('Ada', 36)]Test yourself
2 questionsWhat can a lambda body contain?
Show the answer
A single expression — No if blocks, loops or assignments. A conditional expression is fine, because it is an expression.
Why does [lambda: i for i in range(3)] give three functions that all return 2?
Show the answer
Each looks up i when it runs, by which time the loop has finished — Capture the value with a default argument, lambda i=i: i, which is evaluated at definition time.
Decorators
Wrap a function to add behaviour, without editing the function.