🐍 Python Course · Stage 1 · Lesson 11 of 89 · Lambda Functions
Course Overview →

🟩 Start with the Beginner tab. Read it fully before moving on.

← Functions & Scope Closures →
thecodex.expert · The Codex Family of Knowledge
Python

Lambda Functions in Python

A lambda is a small anonymous function written in a single expression — most useful as a throwaway argument to functions like sorted(), map(), and filter().

Python 3.13 docs.python.org Last verified:
Canonical Definition

A lambda expression creates an anonymous function object. Defined in the Python Language Reference, it consists of the keyword lambda, a parameter list, a colon, and a single expression whose value is returned. Lambdas are syntactically restricted to one expression — no statements, assignments, or annotations.

🟩 Beginner

Tiny anonymous functions

What you will learn: what a lambda is, how it relates to def, and that its body is a single expression whose value is returned automatically.

How to read this tab: Per PEP 8, do not assign a lambda to a name — use def instead. Lambdas are for inline use.

⏱ 20 min📄 1 section🔶 Prerequisite: Functions & Scope
The idea

A lambda is a tiny function with no name, written in one line. lambda x: x * 2 is a function that doubles its input. You use lambdas when you need a small function briefly — usually to hand to another function — and naming it with def would be overkill.

PEP 8: do not assign a lambda to a name. If you are naming it (f = lambda x: ...), use def — it is more readable and gives a proper name in tracebacks. Lambdas exist to be anonymous and inline; the named examples here only show equivalence.

Lambda vs def

A lambda and a def create the same kind of object — a function. The difference is that a lambda is an expression (it can appear inline), has no name, and is limited to a single expression.

Pythonlambda_vs_def.py
# These two are equivalent
def double(x):
    return x * 2

double = lambda x: x * 2        # same behaviour, anonymous origin

print(double(5))   # 10 in both cases

# Lambdas can take multiple arguments
add = lambda a, b: a + b
print(add(3, 4))   # 7

# ...and default arguments
greet = lambda name, greeting="Hello": f"{greeting}, {name}!"
print(greet("Priya"))            # Hello, Priya!
print(greet("Arjun", "Namaste")) # Namaste, Arjun!

# The body is a single EXPRESSION whose value is returned automatically
# (no 'return' keyword, no statements allowed)
square = lambda x: x ** 2
print(square(6))   # 36
PEP 8: don't assign a lambda to a name

If you are giving a lambda a name (double = lambda x: x*2), just use def instead — it is more readable and gives the function a proper name in tracebacks. The whole point of a lambda is to be anonymous and inline. The examples above assign names only to show equivalence.

✅ Beginner tab complete

  • I can write a lambda with one or more arguments
  • I know a lambda body is a single expression (no statements, no return keyword)
  • I know lambda and def create the same kind of object
  • I know not to assign a lambda to a name (use def instead)

Continue to Closures →

🔵 Intermediate

Sort keys, map, filter, reduce

What you will learn: the main legitimate use (sort keys for sorted/min/max), and map/filter/reduce — plus when a comprehension is clearer.

How to read this tab: Default to comprehensions; reach for map/filter mainly with already-named functions.

⏱ 20 min📄 2 sections🔶 Prerequisite: Beginner tab

Sort keys are the ideal lambda use. sorted(people, key=lambda p: p["age"]) is exactly what lambdas are for — a tiny throwaway function passed inline. For multi-level sorting, return a tuple: key=lambda w: (len(w), w).

The main use: sort keys

The single most common and most appropriate use of a lambda is as the key argument to sorted(), min(), max(), and list.sort() — telling them what to compare.

Pythonsort_keys.py
people = [
    {"name": "Priya", "age": 30},
    {"name": "Arjun", "age": 25},
    {"name": "Rohit", "age": 35},
]

# Sort by age
by_age = sorted(people, key=lambda p: p["age"])
print([p["name"] for p in by_age])   # ['Arjun', 'Priya', 'Rohit']

# Sort by name length, then alphabetically (tuple key)
words = ["banana", "kiwi", "apple", "fig"]
print(sorted(words, key=lambda w: (len(w), w)))
# ['fig', 'kiwi', 'apple', 'banana']

# max / min with a key
print(max(people, key=lambda p: p["age"])["name"])   # Rohit
print(min(words, key=len))                           # 'fig' (key=len, no lambda needed)

# Reverse sort
print(sorted([5, 2, 8, 1], key=lambda x: -x))   # [8, 5, 2, 1]
# (or simpler: sorted([5,2,8,1], reverse=True))
💡

Prefer comprehensions over map/filter + lambda. [x*2 for x in nums] reads better than map(lambda x: x*2, nums). Reach for map/filter mainly when you already have a named function to pass, like map(str, nums).

map, filter, and functools.reduce

Pythonmap_filter.py
nums = [1, 2, 3, 4, 5, 6]

# map — apply a function to every item
doubled = list(map(lambda x: x * 2, nums))
print(doubled)   # [2, 4, 6, 8, 10, 12]

# filter — keep items where the function returns True
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens)     # [2, 4, 6]

# reduce — fold a sequence into a single value
from functools import reduce
product = reduce(lambda acc, x: acc * x, nums)
print(product)   # 720 (1*2*3*4*5*6)

# BUT: a comprehension is usually clearer than map/filter+lambda
doubled = [x * 2 for x in nums]          # clearer than map
evens   = [x for x in nums if x % 2 == 0] # clearer than filter
# Reach for map/filter mainly when you already HAVE a named function:
nums_as_str = list(map(str, nums))        # map with a builtin — clean
Commonly confused
Comprehension vs map/filter + lambda. [f(x) for x in xs] is generally more readable than map(lambda x: f(x), xs). Use a comprehension by default; use map/filter when passing an already-named function (e.g. map(str, nums)).
The late-binding closure trap. [lambda: i for i in range(3)] gives three lambdas that all return 2 — they share the variable i. Fix with a default argument: [lambda i=i: i for i in range(3)].

✅ Intermediate tab complete

  • I can use lambda as a key= argument to sorted/min/max
  • I can sort by a tuple key for multi-level sorting
  • I know a comprehension is usually clearer than map/filter + lambda
  • I can recognise the late-binding closure trap in a loop of lambdas

Continue to Closures →

🔴 Expert

Syntactic restrictions and the function object

What you will learn: that a lambda is an ordinary function object with __name__ "", the late-binding fix, and what lambdas cannot do.

How to read this tab: Read to understand exactly why some things require def and produce clearer tracebacks.

⏱ 20 min📄 1 section🔶 Prerequisite: After Stage 1

Syntactic restrictions and the function object

A lambda produces exactly the same type of object as def — a function instance with __code__, __defaults__, and __closure__ attributes. The only differences are syntactic: a lambda's body must be a single expression (no statements, no return, no = assignment, no annotations), and its __name__ is always the string "<lambda>", which is why lambdas produce less helpful tracebacks than named functions.

Pythonlambda_internals.py
f = lambda x, y=10: x + y

# Same object type as a def function
print(type(f))            # <class 'function'>
print(f.__name__)         # '<lambda>'  — always, hence poor tracebacks
print(f.__defaults__)     # (10,)
print(f.__code__.co_argcount)  # 2

# Lambdas capture by reference (closures) — the late-binding trap
funcs = [lambda: i for i in range(3)]
print([fn() for fn in funcs])   # [2, 2, 2]  — all see final i

# Fix 1: default argument binds the CURRENT value
funcs = [lambda i=i: i for i in range(3)]
print([fn() for fn in funcs])   # [0, 1, 2]

# Fix 2: functools.partial
from functools import partial
def identity(i): return i
funcs = [partial(identity, i) for i in range(3)]
print([fn() for fn in funcs])   # [0, 1, 2]

# Conditional expression inside a lambda (allowed — it's an expression)
sign = lambda x: "positive" if x > 0 else "negative" if x < 0 else "zero"
print(sign(-5))   # negative

# What you CANNOT do in a lambda (all SyntaxError):
# lambda x: x = 5          # no assignment
# lambda x: print(x); x    # no statement sequences
# lambda x: return x       # no return keyword

Because the body is restricted to one expression, anything requiring a statement — a loop, a try, multiple steps, or an early return — cannot be a lambda and must be a def. The conditional expression (a if cond else b) is permitted because it is an expression, which lets lambdas express simple branching. For anything beyond a single clear expression, a named function is both required and more readable.

✅ Expert tab complete

  • I know a lambda is the same object type as a def function
  • I know lambda __name__ is always "", giving poor tracebacks
  • I can fix late binding with a default argument: lambda i=i: i
  • I know a conditional expression is allowed in a lambda but statements are not

Continue to Closures →

Sources

1
Python Language Reference §6.14 — Lambdas. docs.python.org/3/reference/expressions.html#lambda.
2
Python Standard Library — sorted(), map(), filter(). docs.python.org/3/library/functions.html.
3
Python Standard Library — functools.reduce. docs.python.org/3/library/functools.html#functools.reduce.
4
PEP 8 — Style Guide: Programming Recommendations (lambda assignment). peps.python.org/pep-0008/.
Source confidence: High Last verified: Primary source: Python Language Reference §6.14