This article mainly introduces decorator instances in Python. This article describes how to call decorator, decorator function definition, decorator application scenarios, and so on, for more information, see decorator. I have already introduced decorator in my previous Blog about Python 2.4 features.
A detailed introduction to decorator has been introduced in What's new in Python 2.4. you can take a look.
How to call decorator
Basically, there are two ways to call decorator:
First:
The code is as follows:
@
Def f ():
This form is written by decorator without parameters. Finally, Python will handle the following:
The code is as follows:
F = A (f)
It can also be expanded:
The code is as follows:
@
@ B
@ C
Def f ():
Finally, Python will handle the following:
The code is as follows:
F = A (B (C (f )))
Note: The document is written in the form of @ A @ B @ C, but actually it cannot be written into multiple lines. In addition, the execution order is in the order of function calls. First, the bottom C, then B, and then. Therefore, if the decorator has a sequence, you must note that the first and last operations must be placed at the bottom. (This inverted relationship should not exist)
Second:
The code is as follows:
@ A (args)
Def f ():
This form is written by decorator with parameters. Then Python will handle the following:
The code is as follows:
Def f ():
_ Deco = A (args)
F = _ deco (f)
As you can see, Python will first execute A (args) to get A decorator function, and then process it in the same way as the first one.
Decorator function definition
Each decorator has corresponding functions. it must process the subsequent functions, either return the original function object or return a new function object. Note that decorator is only used to process functions and class methods.
First:
For the first call form
The code is as follows:
Def A (func ):
# Processing func
# For example, func. attr = 'record'
Return func
@
Def f (args): pass
After processing func, the original function object is still returned. The parameter of this decorator function is the function to be processed. To return a new function, you can:
The code is as follows:
Def A (func ):
Def new_func (args ):
# Do some extra work
Return func (args) # call the original function to continue processing
Return new_func
@
Def f (args): pass
Note that the definition form of new_func should be the same as that of the function to be processed, so it can be written in a common way, such:
The code is as follows:
Def A (func ):
Def new_func (* args, ** argkw ):
# Do some extra work
Return func (* args, ** argkw) # call the original function to continue processing
Return new_func
@
Def f (args): pass
It can be seen that A defines A new function in A, and then A returns this new function. In the new function, we first handle some things, such as checking the parameters or doing some other work, and then call the original function for processing. This mode can be seen as that some processing can be done before the function is called by using the decorator technology. If you want to perform some processing after calling the function, or further, after calling the function, you can perform some processing based on the return value of the function as follows:
The code is as follows:
Def A (func ):
Def new_func (* args, ** argkw ):
Result = func (* args, ** argkw) # call the original function to continue processing
If result:
# Do some extra work
Return new_result
Else:
Return result
Return new_func
@
Def f (args): pass
Second:
For the second call form
As mentioned in the document, if your decorator uses parameters during the call, your decorator function will only use these parameters for calling. Therefore, you need to return a new decorator function, this is consistent with the first form.
The code is as follows:
Def A (arg ):
Def _ A (func ):
Def new_func (args ):
# Do some extra work
Return func (args)
Return new_func
Return _
@ A (arg)
Def f (args): pass
We can see that A (arg) returns A new decorator _.
Decorator application scenarios
But I keep thinking, what is the magic of decorator? Which scenarios are suitable? Do I need to use it?
The magic of decorator is that it can process the modified functions. Therefore, this processing is performed without changing the original function code. I know a little bit about AOP (aspect-oriented programming.
I can think of it as an example:
1. as mentioned in the document, it was initially intended to make it easier to call methods such as staticmethod and classmethod.
2. do some work before executing some functions. for example, in web development, many functions need to check whether the user has logged on before calling them.
3. perform some work after a function is executed. for example, after the call is completed, write logs based on the returned status.
4. check the parameters.
There may be many other things you can imagine
So do I need it?
I think it's about you. However, I think in some cases, using decorator can increase program flexibility and reduce coupling. For example, the user logon check mentioned above. You can indeed write a common logon check function and call it in each function. However, this will cause the function to be inflexible and increase the degree of integration with other functions. If the user login check function is modified, for example, the judgment of the return value has changed, it is possible that every function that uses it must be modified. However, using decorator won't cause this problem. At the same time, the decorator syntax makes the code simple and clear (if you are familiar with its syntax ). Of course you can leave it alone. However, this method of combining functions is more in line with the requirements of building blocks. it can further break down function functions so that functions are simple and simple enough. Then, we can use the decorator mechanism to flexibly concatenate related functions into a string. this is really good. For example:
The code is as follows:
@
@ B
Def account (args): pass
Assume that this is a billing function, and the account only supports billing. However, there are still some judgments and processing for A real accounting, such as B checking the account status and A logging. In fact, this effect is to first check B. through the processing in A, you can first execute the account, and then record the log for processing. It is as convenient as building blocks and easy to change. You can even write the account as a decorator, and the following function is an empty function. Then, you can save the decorator combination through the configuration file and other methods to assemble the functions. Is it ideal.
Python brings infinite creativity!