Detailed explanation of Python decorator from simple to deep, detailed explanation of python from simple to deep

Source: Internet
Author: User
Tags python decorator

Detailed explanation of Python decorator from simple to deep, detailed explanation of python from simple to deep

The functions and names of the decorator are different in many languages. In fact, it represents a design model and emphasizes the principle of openness and closure, it is more used for later functional upgrades than for writing new code. The decorator Can also decorate other objects, such as classes. However, we usually use the decorator function as an example to describe its usage. To understand the working principle of the modifier in Python, you need to step by step. This article tries to be easy to understand, starting with the most basic content.

(Note: The following uses the Python3.5.1 environment)

I. basic functions of Python

First, it must be emphasized that python is executed sequentially from top to bottom, and it will not be executed immediately when it encounters a function-defined code block. Only when the function is called, to execute the internal code block.

Def foo (): print ("the foo function is running! ") In this case, the statements in foo will not be executed. The program simply reads the defined code block into the memory.

Let's take a look at the example of sequential execution:

Def foo (): print ("I am the above function definition! ") Def foo (): print (" I am the following function definition! ") Foo () running result: I am the following function definition

It can be seen that the following foo overwrites the above foo due to sequential execution. Therefore, in Python, code placement is required and cannot be placed at will. The function body must be placed before the called statement.

Secondly, we need to first figure out a few things: function name, function body, and return value, the memory address, function name brackets, function names are treated as parameters, function name brackets are treated as parameters, return function names, and return function names. For the following functions:

Def foo (): print ("let's do something! ") Return" OK "foo ()

Function Name: foo

Function body: Line 1-3

Return Value: string "OK". If the return object is not explicitly given, None is returned by default.

Memory Address of the function: the storage location after the function body is read into the memory, which is referenced by the identifier, that is, the function name foo,
That is to say, foo points to the storage location of the function body in the memory.

Function Name brackets: for example, foo (), function call method. Only when you see this bracket, the program will
Find the function body from the memory and execute it

Let's look at the example below:

Def outer (func): def inner (): print ("I am an inner function! ") Return innerdef foo (): print (" I am the original function! ") Outer (foo ())

In python, everything is an object, and functions are no exception. Therefore, you can call the function name or even function name in parentheses as the return value of another function. In the code above, outer AND foo are two functions. outer (foo) indicates passing the function name of the foo function as a parameter to the outer function and executing the outer function; outer (foo ()) the return value after the foo function is executed is passed to the outer function as a parameter and the outer function is executed. Because the foo function does not specify the return value, it is actually passed to the outer function with a None value. Note the difference. It is critical to have parentheses!

Similarly, inside the outer function, an inner is returned, which is defined within the outer function. Note that because inner is not followed by parentheses, the inner function is returned, it is actually the name of inner, which is a simple reference. What if the outer function returns inner? Now you should know that it will first execute the inner function, then return a None to outer, and outer then returns this None to the object that calls it.

Remember that function names and function brackets can be passed as parameters or return values. There are two completely different meanings of brackets!

Ii. decorator application scenarios

The decorator is usually used to add additional functions for the original function code and functions without changing them. For example, what is executed before the original function is executed, and what is executed after execution.

Let's take an example to see how to use the decorator and how it is designed. (Sorry, I cannot design a better scenario. I can only cite the case of Wu Dashen for deduction)

There is a large company, the basic platform Department of which is responsible for internal application and API development, and hundreds of business departments are responsible for different businesses, they call different functions provided by the basic platform to process their own services, as shown in the following figure:

# The basic platform Department has developed hundreds of functions def f1 (): print ("business department 1 data interface ...... ") def f2 (): print (" Business Department 2 data interface ...... ") def f3 (): print (" business department 3 data interface ...... ") def f100 (): print (" Service Department 100 data interface ...... ") # Each department calls f1 () f2 () f3 () f100 ()

At the early stage of the company's business, the basic platform department did not perform security authentication for function calls for various reasons, such as the time, for example, the lack of weeks. Now, the platform department director decided to make up for this defect, so:

First, the supervisor called an O & M engineer and the engineer ran to the Department one by one to add the authentication function to the Code. However, he was fired on that day.

Second: the supervisor called an O & M engineer again. The engineer wrote a complicated script using shell and barely implemented the function. But he will soon go back and perform O & M. O & M that won't be developed is not good luck ....

Third, the supervisor called a python Automation Development Engineer. The Buddy did this: Only restructured the code on the basic platform, so that N business departments do not need to make any changes. This guy was also launched soon, and even the O & M team had no idea.

Def f1 (): # Add the authentication program code print ("business department 1 data interface ...... ") def f2 (): # Add the authentication program code print (" Business Department 2 data interface ...... ") def f3 (): # Add the authentication program code print (" business department 3 data interface ...... ") def f100 (): # Add the authentication program code print (" business department 100 data interface ...... ") # Each department calls f1 () f2 () f3 () f100 ()

The fourth time: the supervisor changed an engineer. He did this: Define an authentication function, and other functions call it. The Code is as follows. However, the supervisor is still not satisfied, but this time he explained why. The supervisor said: writing code should follow the open and closed principle. Although this principle is mainly for object-oriented development, it is also applicable to functional programming. In short, it specifies that the implemented Function Code cannot be modified internally, but the external code can be extended, that is, closed: Implemented function code block; open: Open to the extension. If the open and closed principle is applied to the above requirements, the code modification within the f1, f2, f3.... f100 function is not allowed. Unfortunately, the engineer did not have a pretty girlfriend, so he was quickly dismissed.

Def login (): print ("authentication successful! ") Def f1 (): login () print (" business department 1 data interface ...... ") def f2 (): login () print (" Business Department 2 data interface ...... ") def f3 (): login () print (" business department 3 data interface ...... ") def f100 (): login () print (" Service Department 100 data interface ...... ") # Each department calls f1 () f2 () f3 () f100 ()

Fifth: there is no time for the supervisor to ask someone to do the job. He decided to go into battle in person and planned to add a log function after function execution. The supervisor thinks this way: the supervisor who does not decorate the device is not a good coders! Why can I be a supervisor? You have to be in charge of it? Hey. The Code is as follows:

#/Usr/bin/env python # coding: utf-8def outer (func): def inner (): print ("authentication successful! ") Result = func () print (" log added successfully ") return result return inner @ outerdef f1 (): print (" business department 1 data interface ...... ") @ outerdef f2 (): print (" Business Department 2 data interface ...... ") @ outerdef f3 (): print (" business department 3 data interface ...... ") @ outerdef f100 (): print (" Service Department 100 data interface ...... ") # Each department calls f1 () f2 () f3 () f100 ()

For the above Code, you only need to expand the code of the basic platform to perform authentication operations before other departments call the f1 f2 f3 f100 function. After the operation, save the logs, in addition, other business departments do not need to modify their own code or change the calling method. After writing the code, the "supervisor" thought it was better to be happy than everyone else, and planned to display it. So he wrote a blog to explain the process in detail.

3. Internal principle of the decorator,

The following describes the f1 function as an example:

Def outer (func): def inner (): print ("authentication successful! ") Result = func () print (" log added successfully ") return result return inner @ outerdef f1 (): print (" business department 1 data interface ...... ")

Use the knowledge we introduced in the first part to analyze the above Code:

  • When the program starts to run and compiled from the top down, it reads def outer (func): when it finds this is a "first-class citizen"-> function, it loads the function body into the memory, then.
  • When I read @ outer, the program was attracted by @, the syntactic sugar. Knowing that this is a decorator, it should be executed immediately according to the rules, the program starts to run the function defined by outer. (I believe no one will be stupid enough to write @ outer to another location. It can only be placed above the top of the decorated function. Do not empty rows .)
  • The program returns to the outer function and starts to execute the decorator's syntax rules. These rules are fixed and "legal" of python. Don't ask why. The rule is: the name of the decorated function is passed to the decorated function as a parameter. After the decoration function executes its own internal code, it will assign its return value to the decorated function.

As shown in:

Note the following:

  • @ Outer and @ outer () are different. If there are no parentheses, the outer function will still be executed. This is different from the traditional brackets to call the function. Pay special attention to this! What about brackets? That is the advanced usage of the decorator. We will introduce it later.
  • It is the function name f1 (instead of f1 () after being called as a parameter) passed to the decoration function outer, that is: func = f1, @ outer equals outer (f1 ), actually, the function body of f1 is passed, rather than the return value after f1 is executed.
  • The return Value of the outer function is the name of the inner function, rather than the return value after the inner () function is called.

If you have a clear understanding of the basic knowledge of the first part of the function, the above content should be easy to understand.

4. The program started to execute the content inside the outer function. At first it encountered another function, which is very difficult, right? Of course, you can arrange other code before and after the inner function, but they are not important and a little troublesome. The following will explain. The inner function definition block is not executed immediately after being observed by the program, but is read into the memory (this is a potential rule ).

5. Next, when we encounter return inner, the return value is a function name, and this function name will be assigned to f1, the decorated function, that is, f1 = inner. Based on the previous knowledge, we know that the f1 function is overwritten by the new function inner (actually, the f1 function name is changed to the memory address of the function body directed to the inner function name, f1 does not point to the memory address of its original function body). When f1 is called later, code in the inner function will be executed, instead of the previous function body. So where did the previous function body go? Do you still remember to pass f1 as a parameter to func? The func variable saves the address of the old function in the memory. With this variable, You can execute the old function body. You can see the result = func () code in the inner function, that's what it does!

6. Next, it is not over yet. When the business department still calls the f1 function through f1 (), the code executed is no longer the code of the old f1 function, but the code of the inner function. In this example, it will first print a "authentication successful" prompt. Obviously, you can replace it with any code. This is just an example. Then, it will execute the func function and assign the returned value a variable result. This func function is the old f1 function. Then, it prints the "log saving" prompt, this is just an example. You can replace it with anything you want. Finally, the variable "result" is returned. We can use r = f1 () to accept the result value in the code of the business department.

7. after completing the above process, you should see that, without making any changes to the Code and interface calling methods of the business department, you have not made any internal changes to the original code of the basic platform department, we only add a decoration function to meet our needs. We need to authenticate the function before calling it, and write logs after calling it. This is the biggest role of the decorator.

Q: Why is it so complicated to create an outer function and an inner function? Isn't one layer of function work?

A: Please note that the @ outer code will automatically execute the code inside the outer function when the program is executed here. If it is not encapsulated, when the business department has not yet performed the call, what has been executed is a bit different from the original intention. Of course, if you have any need for this, it is not impossible. See the following example. It has only one function layer.

Def outer (func): print ("authentication successful! ") Result = func () print (" log added successfully ") return result @ outerdef f1 (): print (" business department 1 data interface ...... ") # The business department has not started executing the f1 function. Execution result: the authentication is successful! Business Department 1 data interface... log added successfully

See? I just defined the function. The business department has not yet called the f1 function, and the program has done all the work. This is the reason for encapsulating a layer of functions.

Iv. parameter transfer of the decorator

Careful friends may have discovered that, in the above example, the f1 function does not have any parameters, and the parameters are required in actual conditions. How can we pass the parameters?

A parameter:

Def outer (func): def inner (username): print ("authentication successful! ") Result = func (username) print (" log added successfully ") return result return inner @ outerdef f1 (name ): print ("% s connecting to business department 1 data interface ...... "% name) # Call method f1 (" jack ")

Add a parameter to the definition part of the inner function to pass this parameter when calling the func function. Is that easy to understand? But the problem arises again. What if the f2 parameter called by another department has two parameters? What if f3 has three parameters? How do you pass it?

It's easy. We have * args and ** kwargs! Known as "omnipotent parameter "! Modify the above Code:

Def outer (func): def inner (* args, ** kwargs): print ("authentication successful! ") Result = func (* args, ** kwargs) print (" log added successfully ") return result return inner @ outerdef f1 (name, age ): print ("% s connecting to business department 1 data interface ...... "% name) # Call method f1 (" jack ", 18)

5. Further Thoughts

Can a function be decorated by multiple functions? Yes! Let's look at the example below!

Def outer1 (func): def inner (* args, ** kwargs): print ("authentication successful! ") Result = func (* args, ** kwargs) print (" log added successfully ") return result return innerdef outer2 (func): def inner (* args, ** kwargs): print ("a welcome message... ") Result = func (* args, ** kwargs) print (" A farewell message... ") Return result return inner @ outer1 @ outer2def f1 (name, age): print (" % s connecting to business department 1 data interface ...... "% name) # method f1 (" jack ", 18) execution result: authentication successful! A welcome message... Jack is connecting to the data interface of business department 1... Log added

Furthermore, can the decorator have its own parameters? Yes! See the following example:

# Authentication function def auth (request, kargs): print ("authentication successful! ") # Log function def log (request, kargs): print (" log added successfully ") # decorator function. Receives two parameters, which must be the name of a function. Def Filter (auth_func, log_func): # The first layer of encapsulation. The f1 function is actually passed to the main_fuc parameter def outer (main_func): # the second layer of encapsulation, auth and log function parameter values are passed here def wrapper (request, kargs): # The Judgment logic of the following code is not important, it is important that the parameter reference and return value before_result = auth (request, kargs) if (before_result! = None): return before_result; main_result = main_func (request, kargs) if (main_result! = None): return main_result; after_result = log (request, kargs) if (after_result! = None): return after_result; return wrapper return outer # note that the decorator function here has parameters, it means to first execute the filter function # And then return the return value of the filter function as the name of the decorator function. So, # Actually, here, Filter (auth, log) = outer, @ Filter (auth, log) = @ outer @ Filter (auth, log) def f1 (name, age ): print ("% s connecting to business department 1 data interface ...... "% name) # Call method f1 (" jack ", 18) running result: authentication successful! Jack is connecting to business department 1 data interface... log added successfully

Dizzy again? In fact, you can understand this by first executing the Filter function, obtaining its return value outer, and then executing the @ outer modifier syntax.

The above is all the content of this article. I hope this article will help you in your study or work. I also hope to provide more support to the customer's home!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.