Decorators Mastery: From Closures to Class Decorators

Learning Objectives: After this lesson, you'll understand closures deeply, build function and class decorators from scratch, use functools effectively, and apply real-world decorator patterns in production code.

How Decorators Transform Functions

Before diving into code, let's visualize what decorators actually do. A decorator wraps a function, adding behavior before and/or after the original function runs.

Loading tool...

When you write @timer above a function, Python replaces that function with the wrapped version. The original function still exists—it's just called from inside the wrapper.

The Foundation: Understanding Closures

Before diving into decorators, we need to solidify our understanding of closures—the mechanism that makes decorators work.

What is a Closure?

A closure is a function that remembers values from its enclosing scope even after that scope has finished executing. Let's visualize how scope works:

Loading tool...

Visualizing Closure Memory

Closures capture variables by reference, not by value. This visualization shows how multiple closures can share the same memory cell:

Loading tool...
Loading tool...

Function Decorators: The Basics

A decorator is simply a function that takes a function as input and returns a new function. Let's trace through the execution:

The Call Stack During Decoration

Loading tool...

The @ Syntax

The @decorator syntax is just syntactic sugar. Here's how stacked decorators work:

Loading tool...
Loading tool...

Preserving Function Metadata with functools

Loading tool...

Decorators with Arguments

Creating decorators that accept arguments requires an extra level of nesting. Let's visualize this three-layer structure:

Loading tool...
Loading tool...

Class-Based Decorators

Decorators can also be implemented as classes using __call__.

Loading tool...
Loading tool...

Decorating Classes

Decorators can also modify classes, not just functions.

Loading tool...

Real-World Decorator Patterns

Authentication and Authorization

Loading tool...
Loading tool...

Caching and Memoization

Loading tool...

Input Validation

Loading tool...

Advanced: Decorators That Work on Methods and Functions

Loading tool...

Practice Exercises

Exercise 1: Rate Limiter Decorator

Loading tool...

Exercise 2: Deprecation Warning Decorator

Loading tool...

Key Takeaways

ConceptDescription
ClosuresFunctions that capture and remember variables from enclosing scope
@wrapsPreserves original function's metadata when decorating
Decorator argumentsRequire factory function that returns the actual decorator
Class decoratorsUse __call__ to make instances callable
Method decoratorsNeed careful handling of self parameter
lru_cacheBuilt-in memoization with LRU eviction

Common Decorator Patterns

  1. Logging/Tracing - Track function calls and results
  2. Timing - Measure execution time
  3. Caching - Store results for repeated calls
  4. Retry - Automatically retry on failure
  5. Validation - Check inputs before execution
  6. Authentication - Verify access permissions
  7. Rate limiting - Control call frequency

Next Steps

In the next lesson, we'll explore Generators and Iterators—learn the iterator protocol, build generators with yield, understand lazy evaluation, and see how generators relate to coroutines and async programming.


Ready to master lazy evaluation? Generators await in the next lesson!