Search code examples
pythonpython-decorators

Python argumented decorator function


I have this example:

def decorator_function_with_arguments(arg1, arg2, arg3):
    def wrap(f):
        print("Inside wrap")
        def wrapped_f(*args):
            print("Pre")
            print("Decorator arguments:", arg1, arg2, arg3)
            f(*args)
            print("Post")
        return wrapped_f
    return wrap

@decorator_function_with_arguments("hello", "world", 42)
def sayHello(a1, a2, a3, a4):
    print('sayHello arguments:', a1, a2, a3, a4)

sayHello("say", "hello", "argument", "list")

The output is:

Inside wrap Pre Decorator arguments: hello world 42 sayHello arguments: say hello argument list Post

I interpret this as follows: The decorator_function_with_arguments gets its 3 args. It outputs a function (wrap) that receives a function and outputs a function, which is the purpose of the decoration. So now wrap will be executed ("Inside wrap" gets printed), the decoration happens, wrap takes sayHello and puts it into wrapped_f, we return. Now if I call sayHello it will be the wrapped version of it, so the rest gets printed out. Ok, but now if i write this:

def argumented_decor(dec_arg1):
    def actual_decor(old_func):
        print("Pre Wrapped")
        def wrapped():
            print("Pre Main")
            print(dec_arg1)
            old_func()
            print("Post Main")
        return actual_decor
    return actual_decor

@argumented_decor("Decor Argument")
def f2():
    print("Main")

f2()

When calling f2 I get the error message: TypeError: actual_decor() missing 1 required positional argument: 'old_func'

Why? argumented_decor gets its argument, actual_decor will be executed, "Pre Wrapped" will be printed, f2 will be wrapped. Now if I call it, it should do as the most inner wrapped function. Why not? I hope I could ask my question understandably. Thanks!


Solution

  • Your actual_decor function returns itself when it should return the wrapper function wrapped:

    def argumented_decor(dec_arg1):
        def actual_decor(old_func):
            print("Pre Wrapped")
            def wrapped():
                print("Pre Main")
                print(dec_arg1)
                old_func()
                print("Post Main")
            return wrapped
        return actual_decor