Skip to content
VLSI Mentor

Python Part I · Module 11 · Functions

lambda: Small Anonymous Functions

Sorting results by runtime needs a function that pulls the runtime out of one result. It is one expression long, it is used in exactly one place, and giving it a name and three lines of definition is more ceremony than the job deserves. Python has a compact form for writing a function where a function is expected, without naming it. It is worth learning precisely, and it is worth learning its limits just as precisely — because it has essentially one good use in the kind of code this course is about, and reaching for it elsewhere produces code that is shorter and worse.

Intermediate14 min readPythonPart IFundamentalsFunctionslambda

Part I · Module 11 · Chapter 11.14 · lambda: Small Anonymous Functions

1. The Problem It Solves

Chapter 5.5 sorted lists of simple values. Real results are not simple values:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = [
    {"test": "burst", "runtime_s": 450},
    {"test": "smoke", "runtime_s": 120},
    {"test": "reset", "runtime_s": 90},
]

Sorting those by runtime means telling sort what to sort by, and the way you tell it is with a function that, given one result, returns the thing to compare. That function is one expression long and is needed in exactly one place.

2. A lambda Is an Ordinary Function Value

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
runtime_of = lambda result: result["runtime_s"]

print(type(runtime_of))
print(runtime_of({"test": "smoke", "runtime_s": 120}))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<class 'function'>
120

<class 'function'> — the same type a def produces. A lambda creates nothing new. It is a second spelling for making a function value, with two restrictions:

  • it has no name of its own
  • its body is one expression, whose value is returned

The syntax is lambda <parameters>: <expression>. No parentheses around the parameters, no return, no block.

Writing runtime_of = lambda ... as above is legal and is not what lambdas are for — if you are giving it a name, write a def, which also lets you add a docstring. Section 8 returns to this. The assignment above exists only to show the type.

3. The Use That Justifies It

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = [
    {"test": "burst", "runtime_s": 450},
    {"test": "smoke", "runtime_s": 120},
    {"test": "reset", "runtime_s": 90},
]

results.sort(key=lambda r: r["runtime_s"])

for r in results:
    print(r["test"], r["runtime_s"])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
reset 90
smoke 120
burst 450

key= takes a function. sort calls it once per item and sorts by whatever comes back — here, the runtime.

The lambda is written exactly where it is used, says what it does in nine characters, and is never referred to again. That is the case where it is the right tool.

Sorting by a different field is a one-word change:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = [
    {"test": "burst", "runtime_s": 450},
    {"test": "smoke", "runtime_s": 120},
    {"test": "reset", "runtime_s": 90},
]

results.sort(key=lambda r: r["test"])

for r in results:
    print(r["test"])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
burst
reset
smoke

4. key= Takes the Function, Not a Call

This is Chapter 11.3 Section 4's rule — a function is a value — arriving where it matters. You hand sort the function itself; sort does the calling:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
names = ["burst", "smoke", "cdc"]

names.sort(key=len)
print(names)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
['cdc', 'burst', 'smoke']

key=len with no parentheses. Sorted by length: 3, 5, 5.

Note what happened to the tie. "burst" and "smoke" are both five characters, and they came back in the order they started in. Python's sort is stable: items the key rates equally keep their original relative order. That is a guarantee, not a coincidence, and it is what makes sorting by one field and then another work at all.

Add the parentheses and it breaks, because you called len with no argument before sort ever saw it:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
names = ["burst", "smoke", "cdc"]

names.sort(key=len())
print(names)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
TypeError: len() takes exactly one argument (0 given)

The same applies to a lambda: key=lambda r: r["test"] hands over a function, and sort supplies each r.

5. No return, Because the Body Is an Expression

The most common first attempt:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
double = lambda n: return n * 2
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
SyntaxError: invalid syntax

return is a statement, and a lambda's body must be a single expression — Chapter 3.1's distinction, enforced. The expression's value comes back automatically:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
double = lambda n: n * 2
print(double(5))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
10

The same restriction rules out everything else statement-shaped: no if statement, no loop, no assignment, no multiple lines. A conditional expression from Chapter 9.6 is allowed, because that is an expression:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
classify = lambda n: "clean" if n == 0 else "failing"

print(classify(0))
print(classify(3))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
clean
failing

That is already at the edge of readable. Two of them nested would not be.

6. sorted() Takes key= Too

Chapter 5.5 introduced both, and Chapter 11.7 Section 8 explained why there are two. Both accept a key:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = [
    {"test": "burst", "runtime_s": 450},
    {"test": "smoke", "runtime_s": 120},
]

by_runtime = sorted(results, key=lambda r: r["runtime_s"])

print(by_runtime[0]["test"])
print(results[0]["test"])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke
burst

sorted() returned a new list and left results in its original order — the non-mutating half of the pair. Use it when the caller's list must not change, which Chapter 11.7 argued should be the default.

Reversing works the same way:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = [
    {"test": "burst", "runtime_s": 450},
    {"test": "smoke", "runtime_s": 120},
    {"test": "reset", "runtime_s": 90},
]

slowest_first = sorted(results, key=lambda r: r["runtime_s"], reverse=True)

for r in slowest_first:
    print(r["test"], r["runtime_s"])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
burst 450
smoke 120
reset 90

7. The Length Limit

The canonical guidance for this chapter is blunt and correct: anything longer than a simple key expression deserves a def.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = [
    {"test": "burst", "runtime_s": 450, "status": "FAIL"},
    {"test": "smoke", "runtime_s": 120, "status": "PASS"},
    {"test": "reset", "runtime_s": 90, "status": "FAIL"},
]

by_status_then_runtime = sorted(
    results,
    key=lambda r: (r["status"], -r["runtime_s"]),
)

for r in by_status_then_runtime:
    print(r["status"], r["test"], r["runtime_s"])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
FAIL burst 450
FAIL reset 90
PASS smoke 120

That one is still readable — a tuple key sorts by the first field, then the second, and the minus reverses the numeric part. Push further and it stops being readable, at which point a named function is better:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
def sort_key(result):
    """Order failures before passes, slowest first within each group."""
    failed_first = 0 if result["status"] == "FAIL" else 1
    return (failed_first, -result["runtime_s"])


results = [
    {"test": "burst", "runtime_s": 450, "status": "FAIL"},
    {"test": "smoke", "runtime_s": 120, "status": "PASS"},
    {"test": "reset", "runtime_s": 90, "status": "FAIL"},
]

for r in sorted(results, key=sort_key):
    print(r["status"], r["test"], r["runtime_s"])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
FAIL burst 450
FAIL reset 90
PASS smoke 120

The named version is three lines longer and gained a docstring explaining the ordering — which the lambda had nowhere to put. That is the real cost of a lambda past a certain size: there is no room for the sentence a reader needs.

8. lambda or def

Questionlambdadef
Has a namenoyes
Bodyone expressionany statements
Can carry a docstringnoyes
Can carry type hintsnoyes
Reusable elsewhereonly via a name, which defeats ityes
Right whena short key or callback, used once, inlineeverything else

Never assign a lambda to a name. double = lambda n: n * 2 and def double(n): return n * 2 produce the same thing, and the second can be documented, annotated and found by name in a traceback. If it needs a name, it is a def.

The honest summary: in automation code of the kind this course builds, key= is the use, and it covers nearly all of them.

9. Predict, Run, Observe

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# A
f = lambda x: x + 1
print("A:", f(1), type(f))

# B
words = ["ccc", "a", "bb"]
print("B:", sorted(words, key=len))

# C
pairs = [("b", 2), ("a", 3), ("c", 1)]
print("C:", sorted(pairs, key=lambda p: p[1]))

# D
nums = [3, 1, 2]
print("D:", sorted(nums, reverse=True), nums)

The verified output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
A: 2 <class 'function'>
B: ['a', 'bb', 'ccc']
C: [('c', 1), ('b', 2), ('a', 3)]
D: [3, 2, 1] [3, 1, 2]

A — an ordinary function value, called normally.

B — key=len without parentheses, sorting by length.

C — the lambda takes each tuple and returns its second field, so the sort is by number.

D — sorted left nums untouched, which is the Chapter 11.7 distinction again.

10. Exercises

Exercise 1 — sort by a field. Given a list of dictionaries with test and seed, sort by seed using a lambda, then by test name. Print both orders.

Exercise 2 — the type. Print the type of a lambda and of a def function. Say in one sentence what that tells you about what lambda creates.

Exercise 3 — the parentheses. Write names.sort(key=len()) and record the exact error. Explain in two sentences what sort was handed and what it needed.

Exercise 4 — no return. Write lambda n: return n * 2, record the error, then fix it. Say which Chapter 3.1 distinction the error is enforcing.

Exercise 5 — mutate or not. Sort a list of results both with .sort(key=...) and with sorted(..., key=...), printing the original after each. Say which you would use in a function that was given the list by its caller, and why.

Exercise 6 — two fields. Sort results by status, and within each status by runtime descending, using a tuple key. Then rewrite it as a named function with a docstring and say which you prefer.

Exercise 7 — lambda or def. For each, choose and justify in one sentence: (a) a key extracting one dictionary field (b) a function used in four places (c) a key needing an if and two lookups (d) a key returning the length of a name.

Exercise 8 — remove the name. Find any name = lambda ... and rewrite it as a def with a docstring and type hints. Say what you gained.

11. Summary

  • lambda <params>: <expression> creates a function value — type() reports function, exactly as a def does.
  • It creates nothing new. It is a second spelling, with two restrictions: no name, and one expression.
  • The body is an expression and its value is returned automatically. return inside one is a SyntaxError.
  • No statements are allowed — no if statement, no loop, no assignment. A conditional expression is fine, because it is an expression.
  • The use that justifies it is key= on sort and sorted.
  • key= takes the function, not a call. key=len, never key=len().
  • sorted() returns a new list; .sort() mutates — Chapter 11.7's pair, and both take key=.
  • A tuple key sorts by several fields in order, and a minus reverses a numeric one.
  • A lambda cannot carry a docstring or type hints, which is what makes it wrong past a short expression.
  • Never assign a lambda to a name. If it needs a name, write a def.

The last chapter of the module puts all of this to work on a real script.

Where this fits

Part of the Python curriculum.