Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A stacked decorator in Python refers to the application of multiple decorators to a single function or method. This technique leverages function composition, where the output (the returned wrapper function) of one decorator becomes the input to the next, creating a nested chain of higher-order functions.

Syntax

Decorators are stacked by placing multiple @decorator_name statements on consecutive lines directly above the target function definition.
@decorator_alpha
@decorator_beta
@decorator_gamma
def target_function():
    pass

Underlying Mechanics

When the Python interpreter evaluates a stacked decorator, it translates the syntactic sugar into standard function calls. The evaluation strictly follows mathematical function composition: f(g(h(x)))f(g(h(x))). The syntax block above is functionally identical to the following reassignment:
def target_function():
    pass

target_function = decorator_alpha(decorator_beta(decorator_gamma(target_function)))

Application vs. Execution Order

Understanding stacked decorators requires distinguishing between application order (when the function is wrapped) and execution order (when the wrapped function is called).
  1. Application Order (Bottom-Up): Decorators are applied from the innermost to the outermost. The decorator closest to the function definition (@decorator_gamma) receives the original function first. Its returned wrapper is then passed to @decorator_beta, and so on.
  2. Execution Order (Top-Down, then Bottom-Up): When the decorated function is invoked, the execution flows through the wrappers from the outermost to the innermost. Code preceding the func() call executes top-down. Code following the func() call executes bottom-up as the call stack unwinds.

Execution Flow Demonstration

The following code illustrates the call stack behavior of stacked decorators:
def outer_decorator(func):
    def wrapper(*args, **kwargs):
        print("1. Entering outer_decorator")
        result = func(*args, **kwargs)
        print("5. Exiting outer_decorator")
        return result
    return wrapper

def inner_decorator(func):
    def wrapper(*args, **kwargs):
        print("2. Entering inner_decorator")
        result = func(*args, **kwargs)
        print("4. Exiting inner_decorator")
        return result
    return wrapper

@outer_decorator
@inner_decorator
def core_function():
    print("3. Executing core_function")


# Invoking the stacked function
core_function()
Standard Output:
1. Entering outer_decorator
2. Entering inner_decorator
3. Executing core_function
4. Exiting inner_decorator
5. Exiting outer_decorator

Metadata Preservation

Because stacked decorators create multiple layers of wrapper functions, the original function’s introspection metadata (__name__, __doc__, __annotations__) is easily masked by the outermost wrapper. To maintain accurate metadata through the entire stack, every decorator in the chain must utilize functools.wraps. If even one decorator in the stack omits it, the metadata chain is broken.
from functools import wraps

def robust_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper
Master Python with Deep Grasping Methodology!Learn More