Functions · Lesson 11 of 18 · 20 min

Closures and decorators

Functions that remember, wrap, and rewrite other functions.

  • Return inner functions that close over state
  • Write a decorator with functools.wraps
  • See late-binding of loop variables

A closure keeps enclosing names alive

When an inner function refers to a name from its enclosing function, Python stores that binding on the function's `__closure__`. The inner function can be returned and called later; the enclosing locals still exist for it.

This is how you manufacture specialized functions without a class: a factory that takes a multiplier and returns a function that uses it.

A tiny factory
def multiply_by(n):
    def inner(x):
        return n * x
    return inner

triple = multiply_by(3)
print(triple(10))
print(triple.__closure__[0].cell_contents)

Decorators are syntactic sugar

`@deco` above `def f():` is `f = deco(f)`. A decorator takes a function and returns a callable, usually a wrapper that runs extra code before or after the original. Stacked decorators apply nearest-first: `@a` then `@b` then `def f` is `f = a(b(f))`.

Always copy metadata with `@functools.wraps(fn)` on the wrapper so `__name__`, `__doc__`, and tools like `inspect.signature` still describe the original.

A tracing decorator
from functools import wraps

def traced(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        result = fn(*args, **kwargs)
        print(f"{fn.__name__}{args} -> {result}")
        return result
    return wrapper

@traced
def add(a, b):
    return a + b

add(2, 3)
print(add.__name__)

Check yourself

Quiz

  1. 1.`@deco` on `def f` is equivalent to:

  2. 2.Why use functools.wraps?

  3. 3.`[lambda: i for i in range(3)][0]()` typically returns:

Practice

Exercise

Write `make_adder(n)` that returns a function adding n to its argument. Write `once(fn)` that returns a wrapper which calls fn only the first time and returns that result forever after.

Tutor

Ask a question about this lesson. Answers are generated on demand and capped so the session stays focused.