Lesson 37
Lambda Functions
Anonymous one-line functions you write inline — perfect for sort keys, filter conditions, and small transformations that don't deserve their own def.
A lambda function is a small, anonymous function you can create on the fly without giving it a name. You write it where you use it. They’re not a replacement for def — they’re a tool for the moments when defining a whole named function would be overkill.
The classic case: you want to pass a tiny “how to compare these” or “how to transform this” function as an argument to something like sorted, map, or filter. Writing a three-line def for a one-line idea hurts readability. A lambda lets you tuck the logic inline.
The syntax
lambda arguments: expression
The keyword lambda, then comma-separated parameters, then a colon, then a single expression that becomes the return value. No def, no return, no name. The whole thing is itself an expression — it evaluates to a function object you can use immediately or assign to a variable.
A first example, kept deliberately small:
add_name = lambda x, y: x + " " + y
full_name = add_name("William", "Mattingly")
print(full_name)
# 'William Mattingly'
That assignment — add_name = lambda ... — is technically legal but stylistically discouraged. If you want to give a function a name, use def. The point of lambda is the times you don’t want a name.
Where lambdas earn their keep — sort keys
The most common, most useful place for a lambda is the key argument to sorted (or list.sort, or min, or max). The key parameter takes a one-argument function that converts each item into the value you want to sort by:
lines = [
"Once upon a midnight dreary, while I pondered, weak and weary,",
"Over many a quaint and curious volume of forgotten lore—",
"While I nodded, nearly napping, suddenly there came a tapping,",
"As of some one gently rapping, rapping at my chamber door.",
]
sorted_lines = sorted(lines, key=lambda line: len(line))
for line in sorted_lines:
print(line)
Each line is converted to its length for the sort, but the result is still the lines themselves, just reordered shortest-to-longest. Compare with the alternative:
def line_length(line):
return len(line)
sorted_lines = sorted(lines, key=line_length)
Both work. The lambda version is a single line and you don’t have to invent a name (line_length, get_length, length_of?) for a function you’ll use exactly once. For sort keys, the lambda is almost always the right call.
The same pattern works for sorting records by a field:
correspondents = [
{"name": "Voltaire", "letters": 21000},
{"name": "Émilie", "letters": 430},
{"name": "Diderot", "letters": 3500},
]
by_letter_count = sorted(correspondents, key=lambda c: c["letters"], reverse=True)
print(by_letter_count[0]["name"]) # 'Voltaire'
This idiom — sorted(records, key=lambda r: r["field"]) — is one you’ll write hundreds of times.
Lambdas with map
map (covered in detail in Lesson 38) applies a function to every item in an iterable. The function it needs is often small enough to be a lambda:
lines = [
"Once upon a midnight dreary, while I pondered, weak and weary,",
"Over many a quaint and curious volume of forgotten lore—",
"While I nodded, nearly napping, suddenly there came a tapping,",
"As of some one gently rapping, rapping at my chamber door.",
]
word_count = map(lambda line: len(line.split()), lines)
print(list(word_count))
# [11, 10, 10, 11]
Read it as: “for each line, compute len(line.split()).” Without the lambda, you’d write a one-line function called something like count_words — fine, but extra noise.
A few honest gotchas
Lambdas are easy to overuse. The cases where they hurt readability:
- One expression, period. A lambda body is a single expression. No
ifstatements (the expression forma if cond else bis fine), no loops, no assignments, noprint. If you need any of those, usedef. - No type hints. A lambda can’t be annotated. Once a function is complex enough that you’d want types on it, write
def. - They have no name in tracebacks. When a lambda raises an error, the traceback says
<lambda>, which is useless. For anything that might fail in production,defis kinder to your future debugging self. - Don’t write a lambda when you mean a function.
f = lambda x: x * 2is strictly worse thandef f(x): return x * 2. Same length, less informative, no docstring, no name in tracebacks. The whole point oflambdais to not assign it.
A useful rule of thumb: if the lambda is the argument to another function (like sorted, map, filter, or a pandas method), you’re probably using it well. If the lambda is being assigned to a variable, you probably want def instead.
Try it yourself
- Sort the list
["Voltaire", "Émilie", "Diderot", "Rousseau"]by name length, shortest first, using a lambda. - Given the
correspondentslist above, usesortedwith a lambda to sort by name (alphabetically). - Use
max(correspondents, key=...)with a lambda to find the correspondent with the most letters. (maxaccepts akeyexactly likesorteddoes.)
Where to next
Lesson 38: The Map Function is the natural next stop — you’ve already seen how a lambda fits inside map; the next lesson goes deeper.
Running the code
Save any snippet from this lesson to a file — say try.py — and run it from your project folder:
uv run try.py
uv run uses the project’s Python and dependencies automatically; no virtualenv to activate. If you haven’t set the project up yet, Lesson 01 walks through it.