Python decorator workshops
Back to WorkshopsGuided JupyterLab workshops that teach Python decorators: what they do, how to write them, and why they work. Standard library only, and they run in the browser.
Launch the workshops
Each option opens the whole collection in a new window, where JupyterLab shows the workshops in the order to take them.
- In browser runs Python inside your browser with JupyterLite. Nothing to install and no account needed. Your work is kept in your browser's storage.
- Binder is a free public service needing no account. Sessions are temporary and can take a minute or two to start.
- Codespaces needs a GitHub account and uses your Codespaces allowance. A codespace is kept until you delete it.
1 What a decorator does 10m
Meet decorators as a user before writing one. Put three decorators from the standard library to work, watch each change what a function or a class does, and find out what the @ line actually means.
2 Your first decorator 20m
Write the thing that goes after the @. Wrap a function by hand, then with the @ syntax, then build a timer, a call counter, and decorators that act before, after and instead of the function they wrap.
3 How a decorator remembers 15m
Find out how a wrapper still knows the function it wraps after the decorator has returned. Open a closure and look inside it, build functions that make functions, keep state with nonlocal, and meet the pitfall that catches everyone once.
4 Decorators that take arguments 15m
Make a decorator work on any function, then make it configurable. Forward arguments with *args and **kwargs, add the extra layer that @repeat(3) needs, build a retry worth keeping, and handle a decorator used with and without parentheses.
5 Preserving the wrapped function 10m
Find out what a wrapper costs you, then fix it with one line. See what functools.wraps copies, why inspect still finds the original signature, and what is genuinely left over.
6 Stacking decorators 15m
Put more than one decorator on a function and find out that they are applied in one order and run in another. See a stack where the order changes the answer, and walk the chain back to the original function.
7 Decorating methods 15m
Put a decorator on a method and meet the most common surprise in Python decorators. See which kinds work, find the instance hiding in args, write a decorator that uses it, and learn the real rule for stacking with staticmethod and classmethod.
8 Decorators that are classes 15m
Write a decorator as a class rather than a function. Keep state in an instance attribute, restore the identity it quietly replaces, use the constructor in place of the extra layer a configurable decorator needs, and see what it still cannot do.
9 How methods bind 20m
Find out how `obj.method()` finds its instance, by doing the binding by hand. Then fix the class-based decorator that could not do it, give a class its own `__get__`, and see that the protocol behind all of it is a plain language feature you can use directly.
10 Decorating classes 15m
Put a decorator on a class rather than a function. Synthesise a `__repr__`, add comparison and meet the hashing trap that comes with it, freeze a class against assignment, and find out that `@dataclass` is an ordinary decorator doing exactly what you have just done by hand.
11 Caching results 15m
Build the decorator you met in the first workshop. Write a naive cache, break it twice, fix the key with signature.bind, then use the standard library's own and find out what unbounded caching costs.
12 Registering functions 15m
Write a decorator that wraps nothing and changes nothing. Build a command registry, a route table and an event system, and recognise the shape you have already used in Flask, Click and pytest.
13 Retrying and handling errors 15m
Decorate the error path. Log a failure without swallowing it, translate an exception while keeping its cause, retry only the failures worth retrying, and watch the stacking order decide what ends up in your logs.
14 Decorating async functions 15m
Put an ordinary decorator on an async def and watch it fail without saying so. Write a wrapper that awaits, one decorator that serves both kinds, and find out what happens when a wrapper blocks the event loop.