Python Lambda Functions: Syntax, Real Uses and When Not to Use Them
A lambda is a tiny function you can write in one line, right where you need it. Learn the syntax, the places lambdas genuinely help, the trap that catches experienced developers, and when a normal function is simply better.
- A lambda is an anonymous function limited to a single expression.
- Its best use is as a short argument, especially the
keyforsorted,minandmax. - A list comprehension is usually clearer than
maporfilterwith a lambda. - If you assign a lambda to a name, write a
definstead.
You need to sort products by price. Writing a separate named function just to say “use the price” feels like a lot of ceremony. Python lambda functions let you define that tiny piece of logic inline, exactly where you use it.
Lambdas are handy, but they are also easy to overuse. This guide shows where they really help and where they make code harder to read. We ran every example on Python 3.13, and the output shown comes from that run.
What is a lambda?
A lambda is a function without a name, written with the lambda keyword:
lambda arguments: expression
It takes any number of arguments and returns the value of a single expression, automatically. There is no return keyword, and no body of statements.
square = lambda x: x * x
print(square(4)) # 16
print((lambda a, b=10: a + b)(5)) # 15
The second line defines a lambda with a default argument and calls it immediately. You would rarely write this in real code, but it shows that a lambda is an ordinary function object.
lambda vs def
These two produce functions that behave the same:
square = lambda x: x * x
def square_def(x):
return x * x
print(square(4), square_def(4)) # 16 16
print(square.__name__, square_def.__name__) # <lambda> square_def
Look at the names. Every lambda is just called <lambda>, so error messages and logs cannot tell you which one failed. This is the main reason style guides such as PEP 8 recommend a def whenever you want to give a function a name.
| Feature | lambda |
def |
|---|---|---|
| Name | Anonymous | Named |
| Body | One expression | Any number of statements |
| Return | Implicit | Explicit return |
| Docstring and type hints | Not supported | Supported |
| Readable tracebacks | Shows <lambda> |
Shows the name |
| Best for | Short throwaway arguments | Everything else |
Sorting with key: the best use
Functions such as sorted, min and max accept a key function that decides what to compare. This is where lambdas shine:
products = [("pen", 10), ("bag", 900), ("book", 250)]
sorted(products, key=lambda p: p[1])
# [('pen', 10), ('book', 250), ('bag', 900)]
max(products, key=lambda p: p[1])
# ('bag', 900)
To sort by several things, return a tuple. Here, people are sorted by age, oldest first, and then by name:
people = [{"name": "Asha", "age": 31}, {"name": "Ben", "age": 25},
{"name": "Dev", "age": 31}]
[p["name"] for p in sorted(people, key=lambda p: (-p["age"], p["name"]))]
# ['Asha', 'Dev', 'Ben']
The minus sign reverses the order for the number only. Sometimes you do not need a lambda at all, because an existing function already does the job. Compare the default sort with a case-insensitive one:
names = ["Asha", "ben", "Chitra", "dev"]
sorted(names) # ['Asha', 'Chitra', 'ben', 'dev']
sorted(names, key=str.lower) # ['Asha', 'ben', 'Chitra', 'dev']
The default puts all capitalized words first. Passing str.lower fixes that without any lambda. The operator module offers similar helpers, such as itemgetter(1) for lambda p: p[1].
map and filter
map applies a function to every item, and filter keeps the items for which it returns true. Both work with lambdas, but compare each with a list comprehension:
nums = [1, 2, 3, 4, 5, 6]
list(map(lambda n: n * 10, nums)) # [10, 20, 30, 40, 50, 60]
[n * 10 for n in nums] # [10, 20, 30, 40, 50, 60]
list(filter(lambda n: n % 2 == 0, nums)) # [2, 4, 6]
[n for n in nums if n % 2 == 0] # [2, 4, 6]
The results are identical, and most Python developers find the comprehensions easier to read. Notice too that map and filter return lazy iterators, so you need list() to see the values. Our guide to Python list comprehension covers that style in depth. map does still read well with an existing named function, as in map(str.strip, lines).
reduce
functools.reduce combines items into a single value, carrying a running result:
from functools import reduce
reduce(lambda acc, n: acc + n, nums, 0) # 21
sum(nums) # 21
For common jobs, such as totals, use a built-in like sum, max or any. Keep reduce for rarer cases, and consider a plain loop if the lambda starts to look complicated.
Conditions in a lambda
You cannot use an if statement in a lambda, but you can use a conditional expression:
label = lambda total: "large" if total >= 1000 else "small"
label(1200), label(300)
# ('large', 'small')
One condition is fine. Once you start nesting them, readers have to work hard, which is a clear sign to switch to a def with ordinary if statements.
Lambdas that return functions
A function can create and return a lambda that remembers a value from its surroundings:
def multiplier(n):
return lambda x: x * n
double = multiplier(2)
double(7) # 14
This works because of closures, which our article on JavaScript closures explains in a different language. Python’s functools.partial offers another way to pre-fill arguments.
The late-binding trap
This catches nearly everyone eventually. We created three lambdas in a loop, expecting each to return its own number:
funcs = [lambda: i for i in range(3)]
[f() for f in funcs]
# [2, 2, 2]
All three return 2. A lambda does not capture the value of i when it is created. It looks up the variable when it is called, and by then the loop has finished, leaving i at 2. The usual fix is to capture the value as a default argument, since defaults are evaluated at definition time:
funcs = [lambda i=i: i for i in range(3)]
[f() for f in funcs]
# [0, 1, 2]
This is not unique to lambdas, as a def inside a loop behaves the same way. It just appears more often with lambdas, because they are so commonly created in loops, such as when attaching button callbacks.
Tip: If you need a function per item, consider whether you need many functions at all. Often a single function that takes the item as an argument is clearer and avoids the trap entirely.
Lookup tables of small functions
Lambdas fit neatly into a dictionary that maps names to small operations:
ops = {
"add": lambda a, b: a + b,
"sub": lambda a, b: a - b,
}
ops["sub"](10, 3) # 7
This can replace a long chain of if and elif. The Python dictionary guide covers more dictionary patterns, and the operator module already provides operator.add and operator.sub.
Limits of lambdas
- One expression only. No assignments with
=, no loops and notryblocks. - No statements. Writing
lambda x: return xfails with aSyntaxError, as our test confirmed. - No docstring or type hints. Tools and readers get less help.
- Harder debugging. Errors point at
<lambda>rather than a helpful name.
Lambdas can still raise exceptions, of course. Handling those works the same as for any function, as covered in Python exception handling.
When not to use a lambda
| Situation | Better choice |
|---|---|
| Assigning it to a name | def |
| Logic needs more than one line | def |
| Transforming or filtering a list | A list comprehension |
| Summing or finding a maximum | sum, max, min |
| Getting an item or attribute | operator.itemgetter or attrgetter |
| The same lambda appears in several places | A named function you can test |
That last point matters. Logic worth reusing is worth testing, and a named function is far easier to test, as our pytest tutorial shows.
Final thoughts
A good lambda is short enough to read at a glance, and used once, usually as an argument. Sorting keys are the classic example. To check your own code, search for = lambda, and turn those into named functions. Then look at any map or filter with a lambda, and see whether a comprehension reads better.
Frequently asked questions
What is a lambda function in Python?
It is a small anonymous function created with the lambda keyword. It takes arguments and returns the value of a single expression, without a name or a return statement.
Can a Python lambda have multiple lines?
No. A lambda is limited to one expression. You can split it over lines inside brackets, but it still cannot contain statements, so use def for more complex logic.
Can I use if else in a lambda?
You can use a conditional expression, such as lambda x: “big” if x > 10 else “small”. An if statement with a block is not allowed.
Are lambdas faster than normal functions?
Not meaningfully. Both create the same kind of function object. Choose between them for readability, not performance.
Should I use map with lambda or a list comprehension?
Most Python developers prefer a list comprehension for readability. map is reasonable when you already have a named function, such as map(str.strip, lines).
Keep learning
Need help with testing, WordPress or SEO?
We help teams ship better software and grow their sites. Tell us what you are working on and we will suggest a clear next step.