All chapters in this track
- 011. Variables, Types & Operators
- 022. Strings
- 033. Lists
- 044. Tuples, Sets & Dicts
- 055. Control Flow
- 066. Error Handling
- 077. Functions & Lambdas
- 088. Comprehensions
- 099. Built-in Functions
- 1010. Type Hints (3.10+)
- 1111. Classes & Dataclasses
- 1212. Iterators & Generators
- 1313. DSA Standard Library
- 1414. Python 3.9–3.11 Features for DSA
- 1515. DSA Idioms & Gotchas
- 1616. Master Quick Reference
Chapter 7 of 16
7. Functions & Lambdas
Tutorial
# ══ FUNCTION DEFINITION ════════════════════════════════════════
def two_sum(nums: list[int], target: int) -> list[int]:
seen: dict[int, int] = {}
for i, x in enumerate(nums):
comp = target - x
if comp in seen:
return [seen[comp], i]
seen[x] = i
return []
# Default arguments
def search(arr: list[int], target: int, lo: int = 0, hi: int = -1) -> int:
if hi == -1: hi = len(arr) - 1
...
# Return multiple values (returns a tuple)
def min_max(arr: list[int]) -> tuple[int, int]:
return min(arr), max(arr)
lo, hi = min_max([3, 1, 4, 1, 5])
# ══ LAMBDAS ════════════════════════════════════════════════════
double = lambda x: x * 2
key_fn = lambda p: p[0]**2 + p[1]**2 # distance from origin
# Most common use: sort key
intervals.sort(key=lambda x: (x[0], -x[1])) # by start asc, end desc
points.sort(key=lambda p: p[0] + p[1])
# ══ *ARGS / **KWARGS ═══════════════════════════════════════════
def sum_all(*args: int) -> int:
return sum(args)
# **kwargs — variable keyword arguments → becomes a dict
def print_info(**kwargs):
for k, v in kwargs.items():
print(f"{k} = {v}")
print_info(name="Alice", age=30)
# Unpack into function arguments
nums = [1, 2, 3]
add(*nums) # add(1, 2, 3)
d = {"a": 1, "b": 2, "c": 3}
add(**d) # same as add(a=1, b=2, c=3)
# ══ NESTED FUNCTIONS & CLOSURES ═════════════════════════════════
# Alternative to nonlocal: mutate a single-element list from the closure
def diameter_v1(root):
result = [0] # list so the inner function can mutate it
def dfs(node):
if not node: return 0
left = dfs(node.left)
right = dfs(node.right)
result[0] = max(result[0], left + right)
return 1 + max(left, right)
dfs(root)
return result[0]
# Python 3 alternative: nonlocal
def diameter(root):
max_d = 0 # outer variable
def dfs(node) -> int:
nonlocal max_d # 3.x: allows mutation of outer scope var
if not node: return 0
l = dfs(node.left)
r = dfs(node.right)
max_d = max(max_d, l + r)
return 1 + max(l, r)
dfs(root)
return max_d
# ══ CACHING ════════════════════════════════════════════════════
from functools import cache, lru_cache
@cache # 3.9+: unbounded memoize
def fib(n: int) -> int:
if n <= 1: return n
return fib(n-1) + fib(n-2)
@lru_cache(maxsize=None) # equivalent to @cache (older style)
def dp(i: int, j: int) -> int: ...
fib.cache_clear() # reset cache between test cases
fib.cache_info() # hits, misses, maxsize, currsize
# ══ cmp_to_key ═════════════════════════════════════════════════
from functools import cmp_to_key
def cmp(a: str, b: str) -> int:
return -1 if a+b > b+a else 1 # largest number sort
strs.sort(key=cmp_to_key(cmp))
Reference
| Feature | Syntax | Notes |
|---|---|---|
| Type hints | def f(x: int) -> str | Not enforced; improves readability |
| Default param | def f(x=0) | Use None for mutable defaults |
| Multiple return | return a, b | Returns tuple; unpack with a,b=f() |
| Lambda | lambda x: expr | Single expression |
| Unpack args | f(*lst) | |
| Memoize | @cache | 3.9+, unbounded |
| LRU cache | @lru_cache(maxsize=N) | Bounded; None=unbounded |
| Clear cache | f.cache_clear() | |
| Outer var | nonlocal x | Modify enclosing scope |
| Custom sort | cmp_to_key(cmp_fn) | cmp returns -1/0/1 |