Skip to content

Advanced Decorators

Beginning of the lesson

Advanced Decorators

Parameterised decorators, class decorators, stacking, and the functools toolkit

Big idea: You already know a decorator is a callable that takes a function and returns a replacement. At the advanced level a decorator is really a small compile-time hook: it runs once, when the def or class statement executes, and it can rewrite the object's identity, add state, register it somewhere, or accept its own configuration. The standard library ships production-grade decorators in functools that you should reach for before writing your own.
By the end of this topic you will be able to:
  • write a parameterised decorator (a decorator factory) and explain its three call layers,
  • build a decorator that works with or without arguments,
  • distinguish the two meanings of class decorator and implement both,
  • reason precisely about the order in which stacked decorators apply and run,
  • apply functools.wraps, lru_cache/cache, and singledispatch, and state their real trade-offs.

1. Parameterised decorators (decorator factories)

A plain decorator takes exactly one argument: the function being decorated. So how does @lru_cache(maxsize=256) take arguments? The trick is one extra layer. @repeat(times=3) is not a decorator; it is a function that returns a decorator. Python first evaluates repeat(times=3), and whatever that returns is then used as the decorator. This gives a parameterised decorator three nested layers.

import functools

def repeat(times):                       # layer 1: the factory, takes the config
    def decorator(func):                 # layer 2: the real decorator, takes the function
        @functools.wraps(func)
        def wrapper(*args, **kwargs):    # layer 3: the wrapper, takes the call args
            result = None
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(times=3)
def ping():
    print("ping")

Read @repeat(times=3) as two steps: d = repeat(times=3) returns decorator, then ping = d(ping). The outermost times is captured by the closure, so every call to the decorated ping repeats three times.

Continue this lesson on YourAIZone

The full lesson has the complete explanation, worked examples, common mistakes, tests with instant checking and an AI tutor. Start right away as a guest, or create an account to keep your progress.

In the full lesson

  • The complete explanation
  • Worked examples
  • Common mistakes and how to avoid them
  • Test questions: 15
  • AI tutor that answers questions about the topic
  • Progress tracking for students, parents and teachers