Python 3.14 ·
✓ verified by execution on 2026-07-28
Closures and Decorators
Closures
A closure is a function that remembers the variables from where it was defined, even after that outer function has returned. The values travel with the function rather than being looked up in the global namespace later.
When you define a function inside another function, the inner function has access to the outer function’s scope. This is called a closure:
A decorator is just a function that takes a function and returns a replacement. Everything else about decorators follows from that one sentence.
Decorators are built on top of closures. They take a function as an argument, and return a new function (the wrapper) that adds some behavior before or after calling the original function:
python
def my_decorator(func): def wrapper(): print("Before the function runs") func() print("After the function runs") return wrapper@my_decoratordef say_hello(): print("Hello!")say_hello()
Output
Before the function runs
Hello!
After the function runs
Your output
The @ syntax is pure convenience. Writing @timer above def work(): is exactly the same as writing work = timer(work) afterwards — the decorator runs once, at definition time, and rebinds the name.
Here is an IP01 interactive visualizer that shows how the @my_decorator syntax is exactly the same as calling say_hello = my_decorator(say_hello):
Write an outer function `make_counter()` that returns an inner function. The inner function should use the nonlocal keyword to increment and return a count starting at 1.