This series of documents:

1. I finally figured out Python decorators (part 1)

2. I finally understand Python decorators (part 2)

3. I finally understand Python decorators (3)

4. I finally understand Python decorators (4)

Advanced use of decorators

Pass the argument to the decorator function

Def a_decorator_passing_arguments(function_to_decorate): def a_wrapper_accepting_arguments(arg1, arg2): print("I got args! Look: {0}, {1}". Format (arg1, arg2)) function_to_decorate(arg1, arg2) return a_wrapper_accepting_arguments # Because when you call a function returned by the decorator, @a_decorator_passing_arguments def print_full_name(first_name, last_name): Print ("My name is {0} {1}". Format (first_name, last_name)) print_full_name("Peter", "Venkman") Look: Peter Venkman #My name is Peter VenkmanCopy the code

Pass the parameters to the decorator

What do you think about passing parameters to the decorator itself?

Because the decorator must accept a function as an argument, this can be awkward.

Therefore, you cannot pass the parameters of the decorator function directly to the decorator.

Before looking for solutions, let’s write a few reminders:

Def my_decorator(func): print("I am an ordinary function") def wrapper(): Print ("I am function returned by the decorator") func() return wrapper # Therefore, you can call it without "@" def lazy_function(): Print (" ZZZZZZZZ ") decorated_function = my_decorator(lazy_function) I am an ordinary function # It prints "I am an ordinary function" because you just called the decorator and did not call the function: Outputs: I am an ordinary function? Outputs: I am an ordinary functionCopy the code

Same result. My_decorator “is called. So, when you use @my_decorator, you tell Python to call the function marked by my_decorator via a variable.

def decorator_maker(): print("I make decorators! I am executed only once: " "when you make me create a decorator.") def my_decorator(func): print("I am a decorator! I am executed only when you decorate a function.") def wrapped(): print("I am the wrapper around the decorated function. " "I am called when you call the decorated function. " "As the wrapper, I return the RESULT of the decorated function.") return func() print("As the decorator, I return the wrapped function.") return wrapped print("As a decorator maker, I return a decorator") return my_decorator # let's create a decorator new_decorator = decorator_maker() # output: #I make decorators! I am executed only once: When you make me create a decorator. #As a decorator maker, I return a decorator Print ("I am the decorated function.") decorated_function = new_decorator(decorated_function) # I am executed only when you decorate a function. #As the decorator, Decorated_function () : I return the wrapped function #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function.Copy the code

Not surprisingly, it’s the same thing we showed you before.

Let’s do the exact same thing again, but this time skip all the pesky intermediate variables:

def decorated_function(): Print ("I am the decorated function.") decorated_function = decorator_maker()(decorated_function) # #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function. # Finally: Decorated_function () # #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function.Copy the code

Let’s make it even simpler:

@decorator_maker() def decorated_function(): print("I am the decorated function.") # I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function. # Finally: Decorated_function () # #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function.Copy the code

Hey, did you see that? We used function calls with @ syntax!

So, back to the decorator with parameters. If we can use a function to generate decorators in real time, we can pass arguments to that function, right?

def decorator_maker_with_arguments(decorator_arg1, decorator_arg2): print("I make decorators! Format (decorator_arg1, decorator_arg2)) def my_decorator(func): # # If you are uncomfortable with wrapping, you can ignore this. print("I am the decorator. Somehow you passed me arguments: {0}, {1}". Format (decorator_arg1, decorator_arg2)) # Do not confuse decorator arguments with function arguments! def wrapped(function_arg1, function_arg2) : print("I am the wrapper around the decorated function.\n" "I can access all the variables\n" "\t- from the decorator: {0} {1}\n" "\t- from the function call: {2} {3}\n" "Then I can pass them to the decorated function" .format(decorator_arg1, decorator_arg2, function_arg1, function_arg2)) return func(function_arg1, function_arg2) return wrapped return my_decorator @decorator_maker_with_arguments("Leonard", "Sheldon") def decorated_function_with_arguments(function_arg1, function_arg2): print("I am the decorated function and only knows about my arguments: {0}" "{1}".format(function_arg1, function_arg2)) decorated_function_with_arguments("Rajesh", "Howard") #I make decorators! And I accept arguments: Leonard Sheldon #I am the decorator. Somehow you passed me arguments: Leonard Sheldon #I am the wrapper around the decorated function. #I can access all the variables # - from the decorator:  Leonard Sheldon # - from the function call: Rajesh Howard #Then I can pass them to the decorated function #I am the decorated function and only knows about my arguments: Rajesh HowardCopy the code

Remember it: decorators with arguments that can take variables as arguments:

c1 = "Penny" c2 = "Leslie" @decorator_maker_with_arguments("Leonard", c1) def decorated_function_with_arguments(function_arg1, function_arg2): print("I am the decorated function and only knows about my arguments:" " {0} {1}".format(function_arg1, Function_arg2)) decorated_function_with_arguments(c2, "Howard") #I make decorators! And I accept arguments: Leonard Penny #I am the decorator. Somehow you passed me arguments: Leonard Penny #I am the wrapper around the decorated function. #I can access all the variables # - from the decorator: Leonard Penny # - from the function call: Leslie Howard #Then I can pass them to the decorated function #I am the decorated function and only know about my arguments: Leslie HowardCopy the code

As you can see, you can pass arguments to the decorator just as any function passes arguments. You can even use *args, **kwargs as needed. Remember, however, that the decorator is only called once, only when Python imports the script. After that, you will not be able to set parameters dynamically. When you execute “import X,” the function is already decorated, so you cannot make any changes.

This article started at BigYoung