Python Lambda Functions: One-Line Functions and Where They Actually Belong
A lambda function is a small anonymous function defined with a single expression. Python’s lambda keyword creates one without a name, without a return statement, and without a body of multiple lines. That constraint is both the source of their usefulness and the reason they should not be used everywhere.
Syntax
lambda parameters: expressionThe result of the expression is automatically the return value. There is no return keyword.
double = lambda x: x * 2print(double(5)) # 10
add = lambda x, y: x + yprint(add(3, 4)) # 7The above examples assign lambdas to names. This is almost never the right choice — if you need a named function, use def. The real value of lambda is in situations where you need a function inline, just for one use.
The Primary Use Case: Sort Keys
The most natural home for a lambda is as the key argument to sorted(), list.sort(), min(), and max(). A key function takes one element and returns the value to sort by.
# Sort a list of tuples by the second elementpairs = [(3, "banana"), (1, "apple"), (2, "cherry")]sorted_pairs = sorted(pairs, key=lambda item: item[1])print(sorted_pairs)# [(1, 'apple'), (3, 'banana'), (2, 'cherry')]
# Sort a list of dicts by a fieldemployees = [ {"name": "Carol", "salary": 68000}, {"name": "Alice", "salary": 75000}, {"name": "Bob", "salary": 82000},]by_salary = sorted(employees, key=lambda e: e["salary"], reverse=True)for emp in by_salary: print(f"{emp['name']}: £{emp['salary']:,}")# Bob: £82,000# Alice: £75,000# Carol: £68,000
# Sort strings by length, then alphabeticallywords = ["apple", "fig", "banana", "kiwi", "plum"]print(sorted(words, key=lambda w: (len(w), w)))# ['fig', 'kiwi', 'plum', 'apple', 'banana']The lambda here is used exactly once, inline. Defining a separate def function would require naming it, placing it somewhere nearby, and then referencing it — more code for less clarity.
map() and filter()
Lambdas work with map() and filter(), but list comprehensions are usually more readable.
numbers = [1, 2, 3, 4, 5, 6, 7, 8]
# Lambda with map and filterevens = list(filter(lambda n: n % 2 == 0, numbers))squared = list(map(lambda n: n ** 2, numbers))
# Equivalent list comprehensions — usually preferredevens = [n for n in numbers if n % 2 == 0]squared = [n ** 2 for n in numbers]For simple one-operation transformations, both are readable. When the expression becomes complex, the comprehension version is almost always clearer because you can read left to right and the result appears first.
Callbacks and Event Handlers
Lambdas are common in frameworks that accept callbacks: GUI toolkits, event systems, schedulers.
# GUI example (tkinter-style)# button = Button(text="Click", command=lambda: handle_click(button_id=3))
# Timer exampleimport threadingdef schedule(delay, callback): timer = threading.Timer(delay, callback) timer.start()
schedule(5, lambda: print("5 seconds elapsed"))
# Sorting a UI list by multiple criteriaitems = [{"label": "B item", "priority": 2}, {"label": "A item", "priority": 1}]items.sort(key=lambda x: (x["priority"], x["label"]))In these contexts, the function is used immediately for one purpose. A named def would be technically equivalent but would create a function that floats in scope, used only in the next line.
Lambda vs def: When to Use Which
| Situation | Use |
|---|---|
| Inline sort key or comparison | lambda |
| One-shot callback in a call | lambda |
| Function needs testing | def |
| Function has a meaningful name | def |
| Logic needs more than one expression | def |
| Function is called in more than one place | def |
| Reading the lambda requires squinting | def |
Python’s style guide (PEP 8) explicitly says: “Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier.” Assigning a lambda to a name is a code smell; it combines the worst of both — the anonymous function has a name, and the name cannot carry a docstring.
# PEP 8 discourages thisis_even = lambda n: n % 2 == 0
# This is clearer and can have a docstringdef is_even(n): """Return True if n is divisible by 2.""" return n % 2 == 0What Lambda Cannot Do
A lambda body is a single expression. It cannot contain:
- Multiple statements
if/elif/elseblocks (though a ternary expression is allowed)- Loops
returnstatements- Assignments with
=(walrus operator:=is allowed in Python 3.8+) yield(generators are not possible in lambdas)
# Ternary in lambda — allowedclassify = lambda n: "positive" if n > 0 else ("negative" if n < 0 else "zero")print(classify(5)) # positiveprint(classify(-3)) # negativeprint(classify(0)) # zero
# But this is often clearer as defdef classify(n): if n > 0: return "positive" if n < 0: return "negative" return "zero"functools.partial as an Alternative
Sometimes you want a lambda to partially apply a function — fix some arguments and leave others open. functools.partial is often more readable.
from functools import partial
def power(base, exponent): return base ** exponent
# Lambda approachsquare = lambda x: power(x, 2)cube = lambda x: power(x, 3)
# functools.partial approach — equivalent but self-documentingsquare = partial(power, exponent=2)cube = partial(power, exponent=3)
print(square(5)) # 25print(cube(3)) # 27partial also handles cases where the lambda would need to do argument reordering, which would make the lambda less clear.