Python Decorators

Back to Labs

Learn Python decorator fundamentals using only Python and its standard library. Core workshops progress from functions as first-class objects and closures through to advanced patterns including class-based decorators, method decoration, and the descriptor protocol. Elective workshops apply these skills to practical domains such as caching, input validation, access control, and plugin systems.

Module A: Decorator Fundamentals

Core concepts of Python decorators from first-class functions and closures through to class-based decorators, the descriptor protocol, async support, metaclasses, and practical applications.

Core Workshops

A01: Functions as Building Blocks

Learn how Python treats functions as first-class objects and how closures capture state from enclosing scopes — foundational concepts for understanding decorators.

Core Beginner 30m

A02: Your First Decorator

Build your first Python decorators by applying the closure and factory patterns — start with manual wrapping, then graduate to the @decorator syntax.

Core Beginner 30m Requires: Functions as Building Blocks,

A03: Decorator Arguments and Flexible Signatures

Build decorators that accept configuration arguments using the decorator factory pattern, and make wrappers that work with any function signature using *args and **kwargs.

Core Intermediate 35m Requires: Your First Decorator,

A04: Preserving the Wrapped Function

Discover how decorating a function silently breaks introspection, then learn to fix it with functools.wraps — and understand the limitations that remain.

Core Intermediate 25m Requires: Decorator Arguments and Flexible Signatures,

A05: Stacking Decorators

Learn what happens when multiple decorators are applied to a single function — how they compose, in what order they execute, and how to reason about the resulting wrapper chain.

Core Intermediate 30m Requires: Preserving the Wrapped Function,

A06: Class-Based Decorators

Implement decorators as classes using __init__ and __call__, and see how instance attributes provide a natural home for per-function state.

Core Intermediate 30m Requires: Preserving the Wrapped Function,

A07: Decorating Methods

Discover why decorating methods differs from decorating standalone functions — experience the breakage caused by class-based decorators on methods and write decorators that are aware of self.

Core Intermediate 30m Requires: Class-Based Decorators,

A08: Decorators and the Descriptor Protocol

Understand the mechanism behind method binding — the descriptor protocol — and use it to fix class-based decorators so they work correctly on both functions and methods.

Core Advanced 35m Requires: Decorating Methods,

A09: Dual-Use Decorators

Build decorators that work both with and without parentheses — @decorator and @decorator(args) — using callable detection, sentinels, and functools.partial.

Core Intermediate 30m Requires: Preserving the Wrapped Function,

A17: Signature Preservation with inspect

Explore the inspect module's signature introspection tools, understand why functools.wraps does not fully preserve signatures, and appreciate why full signature preservation is hard.

Core Advanced 35m Requires: Preserving the Wrapped Function,

A18: Context Manager Decorators

Explore the intersection of decorators and context managers — using contextlib.contextmanager and contextlib.ContextDecorator to build objects usable as both decorators and with statements.

Core Intermediate 35m Requires: Preserving the Wrapped Function,

A19: Thread Safety and Decorators

Build synchronisation decorators using threading.Lock and threading.RLock — demonstrating race conditions, per-function vs per-instance locking, and reentrant locks for recursive calls.

Core Advanced 35m Requires: Preserving the Wrapped Function,

A20: Decorators for Async Functions

Master the challenges of decorating async def functions — write async decorators that properly await the wrapped coroutine and detect whether a function is async at decoration time.

Core Intermediate 35m Requires: Preserving the Wrapped Function,

A21: Class Decorators

Discover that decorators can be applied to classes as well as functions — modify class attributes, add methods and properties, and compare class decorators with metaclasses and __init_subclass__.

Core Advanced 40m Requires: Stacking Decorators,

A22: Decorators and Metaclasses

Use metaclasses to automatically apply decorators to all methods of a class, learn how __init_subclass__ offers a simpler alternative, and understand when metaclasses are necessary.

Core Advanced 40m Requires: Class Decorators,

Elective Workshops

A10: Input Validation Decorators

Build decorators that validate function arguments at runtime — using inspect.signature to bind arguments, reading type annotations, and composing reusable constraint factories.

Elective Intermediate 35m Requires: Preserving the Wrapped Function,

A11: Caching and Memoisation Decorators

Build memoisation decorators from scratch — handling cache keys, keyword arguments, and eviction — then compare with functools.lru_cache and implement time-based cache expiry.

Elective Intermediate 35m Requires: Preserving the Wrapped Function,

A12: Access Control Decorators

Build permission-checking decorators that gate function access based on user authentication and roles — including @login_required, @requires_role, and method-level access control.

Elective Intermediate 35m Requires: Preserving the Wrapped Function,

A13: Registration and Plugin Decorators

Build decorators that register functions in central registries — including a command dispatcher, a route system, and an event hook system — exploring the pattern where the decorator records rather than wraps.

Elective Intermediate 35m Requires: Preserving the Wrapped Function,

A14: Exception Handling Decorators

Build decorators that catch, log, transform, and retry on exceptions — including structured logging, exception mapping, exponential backoff with jitter, and conditional suppression.

Elective Intermediate 35m Requires: Preserving the Wrapped Function,

A15: Deprecation Decorators

Build configurable @deprecated decorators using the warnings module — covering stacklevel for correct call-site reporting, versioned deprecation, and automatic redirect to replacement functions.

Elective Intermediate 30m Requires: Preserving the Wrapped Function,

A16: Profiling and Measurement Decorators

Build decorators that measure function execution time, call frequency, and memory usage — using time.perf_counter_ns(), tracemalloc, and cProfile.

Elective Intermediate 35m Requires: Preserving the Wrapped Function,