Understand functions as first-class objects and closures
Write and apply decorators with @decorator syntax
Use functools.wraps to preserve function metadata
Build custom context managers with __enter__/__exit__ and @contextmanager
💻 Decorator Step Simulator
Step through how a timing decorator wraps a function and measures its execution time.
Code
State
Output
Functions Are First-Class Objects
In Python, functions are objects. You can assign them to variables, pass them as arguments, return them from other functions, and store them in data structures. This is the foundation that makes decorators possible.
Decorators
A decorator is a function that takes another function and returns a modified version. The @decorator syntax is just syntactic sugar for func = decorator(func). Decorators are used throughout real codebases: Flask uses @app.route, Django uses @login_required, pytest uses @pytest.mark.parametrize.
Always use @functools.wraps(func) inside your wrapper — it preserves the original function's name and docstring.
Context Managers
A context manager controls setup and teardown around a block of code. The with statement calls __enter__ at the start and __exit__ at the end (even if an exception occurs). Build them as classes or with @contextlib.contextmanager and yield.
Quick Check
1. What does @timer above a function definition do?
Adds a time attribute to the function
Replaces the function with timer(function) — the decorated version
Imports the time module automatically
Makes the function run asynchronously
2. Why use functools.wraps(func) inside a decorator?
It makes the decorator run faster
It preserves the original function's __name__ and __doc__ attributes
It prevents the decorator from being applied twice
It automatically logs the function's arguments
3. When does __exit__ run in a context manager?
Only when the with block completes without errors
Always — when the with block exits, regardless of whether an exception occurred
Only when an exception is raised inside the with block
When the garbage collector runs
4. What does a closure capture?
The entire global namespace
Variables from the enclosing scope at the time the inner function is defined