Advanced Python Decorators: Passing Arguments to Your Wrappers

3D illustration of a function wrapper with adjustable control dials, representing passing arguments to Python decorators.

In our Basic Decorator Guide, we built a simple @log_decorator. But what if we want to configure the decorator itself? Like this: @repeat(times=5)

To achieve the configuration needed in advanced Python decorators, we need three levels of nested functions. It looks confusing at first, but it follows a pattern.

The Pattern

  1. Outer Function: Accepts the decorator’s arguments (e.g., times=5).
  2. Middle Function: Accepts the function being decorated (standard decorator).
  3. Inner Function: The actual wrapper that runs the code.
# 1. Outer level receives the arguments
def repeat(times):
    # 2. Middle level receives the function
    def decorator_func(original_func):
        # 3. Inner level wraps the logic
        def wrapper_func(*args, **kwargs):
            for _ in range(times):
                original_func(*args, **kwargs)
        return wrapper_func
    return decorator_func

Using It

Now we can utilise advanced features offered in Python decorators and employ our configurable decorator!

@repeat(times=3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

Output:

Hello, Alice!
Hello, Alice!
Hello, Alice!

This is exactly how complex frameworks like Flask allow you to do @app.route("/home", methods=["GET", "POST"]).

Similar Posts

Leave a Reply