Definitions, every kind of argument, scope, lambdas with map/filter/sorted, closures, decorators and generators.
xs = [3, 1, 2]
pairs = [("a", 3), ("b", 1)]def greet(name):
return f"Hello, {name}"
greet("Ada")def, a body, return. Without return the result is None.
def power(x, n=2):
return x ** n
power(3), power(3, 3)Default argument → 9, 27.
power(n=3, x=2)Keyword arguments can come in any order.
def divmod2(a, b):
return a // b, a % b
q, r = divmod2(7, 2)Return several values as a tuple and unpack them.
def add(items, acc=None):
acc = [] if acc is None else acc
acc.extend(items)
return accNever use a mutable default (acc=[]): it is shared between calls.
def fact(n):
return 1 if n <= 1 else n * fact(n - 1)
fact(5)Recursion → 120; the default depth limit is 1000.
def f(a: int, b: str = "x") -> str:
"""Return b repeated a times."""
return b * a
f.__doc__, f.__name__Type hints and docstring are metadata; they are not enforced.
def total(*args):
return sum(args)
total(1, 2, 3)*args collects extra positional arguments into a tuple.
def tag(**kwargs):
return kwargs
tag(a=1, b=2)**kwargs collects extra keyword arguments into a dict.
def f(a, b, *args, key=None, **kwargs):
return a, b, args, key, kwargs
f(1, 2, 3, key="k", z=9)The full order: positional, *args, keyword-only, **kwargs.
def area(w, h):
return w * h
dims = (3, 4); opts = {"w": 2, "h": 5}
area(*dims), area(**opts)Unpack a sequence / a mapping into arguments.
def f(a, /, b, *, c):
return a + b + c
f(1, 2, c=3)Before / is positional-only, after * is keyword-only.
from functools import partial
square = partial(pow, exp=2)
square(5)Freeze some arguments → 25.
counter = 0
def bump():
global counter
counter += 1
bump()Assigning to a module-level name inside a function needs global.
def make_counter():
n = 0
def inc():
nonlocal n
n += 1
return n
return inc
c = make_counter(); c(); c()Closure keeps n alive; nonlocal lets the inner function rebind it → 2.
def multiplier(k):
return lambda x: x * k
double = multiplier(2)
double(21)Function factory → 42.
fns = [lambda x, i=i: x + i for i in range(3)]
[f(10) for f in fns]Bind the loop variable as a default, or every lambda sees the last i.
square = lambda x: x * xAnonymous single-expression function (def is clearer when named).
sorted(pairs, key=lambda p: p[1])Sort by the second item → [('b', 1), ('a', 3)].
list(map(lambda x: x + 1, xs))→ [4, 2, 3]; a comprehension does the same.
list(filter(lambda x: x > 1, xs))→ [3, 2].
from functools import reduce
reduce(lambda a, b: a * b, [1, 2, 3, 4])Fold left → 24.
from operator import itemgetter
sorted(pairs, key=itemgetter(1))Faster, named alternative to lambda p: p[1].
import operator
ops = {"+": operator.add, "*": operator.mul}
ops["*"](6, 7)Functions are values: store them in dicts, pass them around.
callable(len), callable(3)→ True, False.
import functools
def log(fn):
@functools.wraps(fn)
def wrapper(*a, **kw):
print("calling", fn.__name__)
return fn(*a, **kw)
return wrapper
@log
def add(a, b): return a + b
add(1, 2)A decorator takes a function and returns a replacement; wraps keeps the name and docstring.
def repeat(n):
def deco(fn):
def wrapper(*a):
return [fn(*a) for _ in range(n)]
return wrapper
return deco
@repeat(3)
def hi(): return "hi"
hi()A decorator with arguments is a function that returns a decorator.
from functools import cache
@cache
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
fib(80)Memoise; lru_cache(maxsize=128) bounds the cache.
import time
def timed(fn):
def w(*a, **kw):
t = time.perf_counter(); r = fn(*a, **kw)
print(f"{fn.__name__}: {time.perf_counter() - t:.4f}s")
return r
return wThe usual timing decorator.
def countdown(n):
while n > 0:
yield n
n -= 1
list(countdown(3))yield makes a lazy generator → [3, 2, 1].
g = countdown(2)
next(g), next(g), next(g, "done")next() pulls one value; a default avoids StopIteration.
def flat(rows):
for row in rows:
yield from row
list(flat([[1, 2], [3]]))yield from delegates to an inner iterable → [1, 2, 3].
def read_big(path):
with open(path) as f:
for line in f:
yield line.rstrip()Stream a file line by line without loading it all.
import inspect
str(inspect.signature(print))Introspect any callable's parameters.
Want the topic explained, not just listed? The Functions lesson walks through it with graded exercises. Preparing for interviews? See the interview prep track.