Lambda Basics
What is a Lambda?
A lambda is an anonymous (unnamed) function defined in a single expression.
# Regular function
def add(a, b):
return a + b
# Lambda equivalent
add = lambda a, b: a + b
print(add(2, 3)) # 5
Lambda Syntax
# lambda arguments: expression
# No arguments
greet = lambda: 'Hello!'
print(greet()) # Hello!
# Single argument
double = lambda x: x * 2
print(double(5)) # 10
# Multiple arguments
add = lambda a, b: a + b
print(add(2, 3)) # 5
# Default arguments
power = lambda x, n=2: x ** n
print(power(3)) # 9
print(power(3, 3)) # 27
# *args and **kwargs
custom = lambda *args, **kwargs: (args, kwargs)
print(custom(1, 2, 3, key='value'))
# ((1, 2, 3), {'key': 'value'})
Lambda vs def
# Lambda:
# - Single expression only
# - Anonymous (no name unless assigned)
# - Returns value automatically
# - No type hints
# - No docstring
# - No annotations
# def:
# - Multiple statements allowed
# - Named function
# - Explicit return needed
# - Supports type hints
# - Supports docstring
# - More readable
# ✅ Use lambda for short, simple functions
# ✅ Use def for complex functions
Lambda Use Cases
Sorting with Key Functions
# Sort by length
words = ['banana', 'pie', 'Washington', 'cat']
words.sort(key=lambda w: len(w))
print(words) # ['pie', 'cat', 'banana', 'Washington']
# Sort by second element
pairs = [(1, 'b'), (3, 'a'), (2, 'c')]
pairs.sort(key=lambda p: p[1])
print(pairs) # [(3, 'a'), (1, 'b'), (2, 'c')]
# Sort dictionaries by value
users = [
{'name': 'Alice', 'age': 30},
{'name': 'Bob', 'age': 25},
{'name': 'Charlie', 'age': 35}
]
users.sort(key=lambda u: u['age'])
print(users) # Sorted by age
With map() and filter()
numbers = [1, 2, 3, 4, 5]
# map: transform each element
doubled = list(map(lambda x: x * 2, numbers))
print(doubled) # [2, 4, 6, 8, 10]
# filter: keep elements that match
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4]
# Better with list comprehensions
doubled = [x * 2 for x in numbers]
evens = [x for x in numbers if x % 2 == 0]
As Arguments
# Passing function as argument
def apply(func, value):
return func(value)
print(apply(lambda x: x ** 2, 5)) # 25
print(apply(lambda x: x.upper(), 'hello')) # HELLO
# In reduce
from functools import reduce
product = reduce(lambda a, b: a * b, [1, 2, 3, 4, 5])
print(product) # 120
Conditional Expressions
# Ternary in lambda
is_even = lambda x: 'even' if x % 2 == 0 else 'odd'
print(is_even(4)) # even
print(is_even(5)) # odd
# Absolute value
abs_val = lambda x: x if x >= 0 else -x
print(abs_val(-5)) # 5
# Max of three
max3 = lambda a, b, c: a if a > b and a > c else (b if b > c else c)
print(max3(1, 2, 3)) # 3
Lambda Pitfalls & Best Practices
Common Pitfalls
# ❌ Closure variable binding issue
funcs = [lambda x: x + i for i in range(5)]
results = [f(0) for f in funcs]
print(results) # [4, 4, 4, 4, 4] - All use i=4!
# ✅ Fix: use default argument
funcs = [lambda x, i=i: x + i for i in range(5)]
results = [f(0) for f in funcs]
print(results) # [0, 1, 2, 3, 4]
# ❌ Overly complex lambda
complex = lambda x: x ** 2 + 2 * x + 1 if x > 0 else -x ** 2 + 2 * x - 1
# ✅ Use def for complex logic
def complex_func(x):
if x > 0:
return x ** 2 + 2 * x + 1
return -x ** 2 + 2 * x - 1
When to Use Lambda
# ✅ Good use cases:
# 1. Short key functions
sorted(data, key=lambda x: x.lower())
# 2. Quick transformations
list(map(lambda x: x ** 2, numbers))
# 3. Conditional logic in comprehensions
[lambda x: x * 2 if x > 0 else x for x in numbers]
# 4. GUI callbacks (when simple)
button.on_click(lambda: print('Clicked'))
# ❌ Bad use cases:
# 1. Named function needed
process = lambda x: x * 2 # Bad
# Better:
def process(x):
return x * 2
# 2. Complex logic
complex = lambda x: (x ** 2 + 2 * x + 1 if x > 0 else -x ** 2 + 2 * x - 1)
# 3. Reusable function
add_one = lambda x: x + 1 # Bad if used frequently
# Better:
def add_one(x):
return x + 1
Debugging Lambdas
# Lambdas are hard to debug
def debug_lambda(func):
def wrapper(*args, **kwargs):
print(f'Calling {func.__name__} with {args}, {kwargs}')
result = func(*args, **kwargs)
print(f'Result: {result}')
return result
return wrapper
# Use for debugging
add = debug_lambda(lambda a, b: a + b)
add(2, 3)
# Calling <lambda> with (2, 3), {}
# Result: 5