Because I learned from the video, and the content in the video is limited. Basically, I will go to the Internet to find information to deepen and expand it, but the decorator really baffles me. Listen to the video How to use the decorator, how to find information on the Internet, and how to use the decorator, but just because of how to use the decorator, can't I even use it correctly at the beginning?
Whether it's a video or an online blog, when we talk about the decorator, we only talk about what the decorator is and how to use it. However, no one talks about the precautions of the decorator. As a result, people who just touch the decorator will bump into the wall and report various errors. (because the modifier is the same as the def function we usually use, but no one says that the use of the modifier is different from that of the ordinary function, so it is misleading.)
Read a lot of blogs, do a lot of experiments with others' blogs, knock out a lot of code, at first there will be errors, even follow the blog content. Because basically the blog doesn't put the running result chart, there are many duplicate materials to find, and many blog codes are too deep, it's a bit difficult for me who can't even use the decorator correctly.
So I combined with other blogs at the same time, I also summed up the use methods and precautions. I believe that after reading this article, the logic of the decorator can be straightened out.
Last but not least, we should learn the principle first, be familiar with the principle and then expand it. No matter what the grammar is, we should learn the grammar and rules first. When the amount of code is up, the grammar principle is OK, and then we start to move to a higher level. So in the early stage, when we look for information on the Internet, we should learn to filter the grammar actively Don't pay attention to the meaning of the function code in the unreadable code, but to the grammar!
Decorator: the decorator is essentially a function, which is used to handle other functions. It allows other functions to add additional functions without modifying the code (called decorator Decoration, similar to AOP). The return value of the decorator is also a function object. It is often used in scenarios with faceted requirements, such as: insert log, performance test, transaction processing, cache, permission verification and other application scenarios. Decorator is a perfect design to solve this kind of problem. With decorator, we can extract a lot of similar code which has nothing to do with function function itself and continue to reuse it. Generally speaking, the function of decorators is to add additional functions to existing objects.
If the text is a little difficult to understand, let's take a picture to see what the decorator is
The python execution process we understood before is as shown in Figure 1.1
If we add A modifier to the function (as shown in Figure 1.2), when the program executes function A, the system will detect that there is A modifier on function A, and then the system will execute the procedure in the modifier first and then return to the content of the function
Note: the line coming back from the modifier is not necessary. It needs to write back statements in the modifier back to the function. There will be the following statement (called the parameters of the first level function in the two level function).
When we talk about the function of modifiers, let's talk about the requirements first, when can we use them to get modifiers.
For example, I now have a function
def ccx(): print('my name is ccx') print('I want to know the time')
If I want to know the current time, the normal way is to add functions to the current function, right? So add the time code as follows
import time def ccx(): print('my name is ccx') print('I want to know the time') print(' | ^ - ^ |' * 5) start = time.time() start1 = time.asctime(time.localtime(time.time())) print('The current timestamp is:', start) print('The current time is:', start1) ccx()
The above is the general method of adding time in a function. But if we have 10 functions, 100 functions need to add this time method??? Copy code and paste it one by one? If so, I'll use python for my short life, which is a contradiction. So there are modifiers.
The function code of the modifier can be customized. You only need to know the syntax and how to define it. How to play the function code of the modifier later.
def name(x): def name1(): # Function code block x() #Call parameter. If this parameter is not added, the contents of the function will not be called. # Function code block return name1()
For example: now define a finisher to realize the printing time!
# Define a time decorator import time # Time module def test(func): def wrapper(): start = time.time() start1 = time.asctime(time.localtime(time.time())) func() # Used to output function contents time.sleep(5) #Sleep for 5 seconds end = time.time() end1 = time.asctime(time.localtime(time.time())) print('start Time stamp is:',start) print('start The current time is:', start1) print('end Time stamp is:',end) print('end The current time is:',end1) return wrapper()
Note that if you define a decorator alone, there is no output when you run it!!! Because there is no call!
Method: add the @ modifier name to the function using the decorator. python's decorator is a kind of syntax sugar (icing syntax)
For example, now create a ccx() function to call the time display decorator!!!
# Define a time decorator import time # Time module def test(func): def wrapper(): start = time.time() start1 = time.asctime(time.localtime(time.time())) func() # Used to output function contents time.sleep(5) #Sleep for 5 seconds end = time.time() # time stamp end1 = time.asctime(time.localtime(time.time())) # time print('start Time stamp is:',start) print('start The current time is:', start1) print('end Time stamp is:',end) print('end The current time is:',end1) return wrapper() @test # Using decorators def ccx(): print('my name is ccx') print('I want to know the time')
Note: using the modifier, the function cannot be called, otherwise an error will be reported!!! Because the modifier has its own call, can not be called alone!!! Error reported after calling is as follows!!!
Analyze the execution process, and use the decorator to perform the effect equal to the following figure:
Here are some extensions. If you are interested, please take a look at them.
The example given in the second edition of python 3 Program Development Guide (hereinafter referred to as the guide) is a small decorator that is more interesting for python Beginners (no project involved). If you are interested in it, you can have a look at it. I have made some comments on it
def positive_result(function): def wrapper(*args, **kwargs): # Result get the return value of the function and judge the result result = function(*args, **kwargs) # assert asserts that if the return value of the function function is greater than or equal to 0, an AssertionError exception will be generated for assert result >= 0, function.__name__ + "() result isn't >= 0" # return return result # Setting the wrapper's docstring and name to be the same as the original function is conducive to introspection (getting its own information) wrapper.__name__ = function.__name__ wrapper.__doc__ = function.__doc__ return wrapper # Use positive_result decorator @positive_result def discriminant(a,b,c): return (b**2) - (4*a*c) print(discriminant(0,6,5)) print(discriminant(2,6,5))
A simplified version of this example is given in the guide, which uses functools.wraps(function)
def positive_result(function): # Wrapper itself uses the function tools module's@ functools.wraps Wrap, which ensures that the name of the wrapper is the same as docstring and function @functools.wraps(function) def wrapper(*args, **kwargs): result = function(*args, **kwargs) assert result >= 0, function.__name__ + "() result isn't >= 0" return result return wrapper
- Modifier parameterization
Now we have learned what a decorator is and how to use it. In the above log decorator, our log information is often written to a file, but different functions need to write different file names, so a simple @ decorator name can no longer meet the needs. At this time, we need to parameterize the decorator, Passing the filename to be operated to the test() function
Now let's take an example from the guide
import functools def bounded(mininum, maxinum): def decorator(function): @functools.wraps(function) def wrapper(*args, **kwargs): result = function(*args, **kwargs) if result < mininum: return mininum elif result > maxinum: return maxinum return result return wrapper return decorator @bounded(0,100) def percent(amount, total): return (amount / total) * 100 percent(15,100)
The implementation process is as follows: