What are lambda functions, and when should you avoid them?
Quick Answer
A lambda is an anonymous, single-expression function. lambda x: x * 2 is equivalent to a def with one return statement, but has no name, no statements (only one expression), and no docstring. Use lambdas for short, throwaway callbacks (sorted(key=lambda x: x.name)). Avoid them for anything that needs a name for debugging/tracebacks, has multiple logical steps, or would benefit from a docstring — PEP 8 explicitly recommends def over binding a lambda to a name.
Detailed Answer
What a lambda is
square = lambda x: x * x
# equivalent to:
def square(x):
return x * x
A lambda is restricted to a single expression — no statements (no
if/for blocks, no multiple lines, no assignments other than the
walrus operator inside the expression). Its return value is always that
one expression's result.
Good uses: short, inline, throwaway callbacks
people.sort(key=lambda p: p.last_name)
sorted(words, key=lambda w: (-len(w), w))
list(filter(lambda x: x % 2 == 0, numbers))
button.on_click(lambda: print("clicked"))
These are idiomatic. The lambda exists only to describe "how to sort/ filter this," used once, right where it's needed. Naming it separately would add indirection without adding clarity.
Why PEP 8 discourages binding a lambda to a name
# PEP 8: don't do this
f = lambda x: x * 2
# do this instead
def f(x):
return x * 2
Once you're naming the function anyway, def is strictly better:
- Tracebacks show the real name. A named lambda's
__name__is literally"<lambda>", which makes stack traces harder to read. defsupports a docstring, statements, multiple lines, and default values with the same clarity as any other function.- No expressiveness advantage — a bound lambda can't do anything a
one-line
defcan't, so there's no upside to the restriction.
Lambdas can't contain statements — a common trip-up
lambda x: print(x); return x # SyntaxError -- can't have multiple statements
lambda x: x if x > 0 else -x # OK -- this is a conditional EXPRESSION, not a statement
A conditional expression (a if cond else b) is fine inside a lambda.
Actual statements (if, for, try, assignment, return) are not.
Lambdas are single-expression anonymous
functions, ideal for short inline callbacks like sort keys or simple
filters. The moment a lambda is complex enough to need a name, multiple
steps, or a docstring, write a regular def instead. PEP 8 treats
name = lambda: ... as an anti-pattern.