[Python] I will share some of my experiences with the Python decorator for your reference.

Source: Internet
Author: User
Tags python decorator

[Python] I will share some of my experiences with the Python decorator for your reference.
Recently, I wrote a py script to sort out documents on the computer, including the characters that need to be checked and entered. In order not to make the code lengthy, I thought of using the decorator.

Search for python-related learning documents online. I mainly read a blog post on AstralWind and an article on Limodou. As a beginner, these two articles are of great help to beginners, but they are still difficult to understand. Therefore, I would like to record the learning experience of the python decorator with the knowledge of a beginner.

 

1. What is a decoration device?

 

As the name suggests, the decorator marks a method name with the @ symbol above the method to embellish the decorated method.

When you understand what a decorator is, you will naturally feel that the name is correct, but as a beginner, it will be somewhat confused. The following code describes how to understand the decorator.

 

# Script 1def target (): print ('this is target') def decorator (func): func () print ('this is recorator') decorator (target) ----------------------------------------- the running result is: this is targetthis is decorator

 

Python allows the method to be passed as a parameter. Therefore, the above script is to pass the target method as a parameter to the decorator method. This is also the working principle of the decorator. The above code is equivalent:

 

# Script 2def decorator (func): func () print ('this is recorator') @ decoratordef target (): print ('this is target') target ------------------------------------- running result: this is targetthis is decorator

 

Therefore, we can see that the so-called decorator uses the Python method to pass Parameters, and passes the method target as a parameter to the method decorator.

 

@decoratordef target():    ...

 

Adding a @ symbol above a method means that the method located below will be passed as a parameter to the decorator method located behind. Using the @ symbol only changes the code in script 1 into a better way. Of course, it will be more flexible and practical. This will be discussed later.However, they are essentially the same, that is, the working principle of the decorator.

 

2. decorator Principle

 

If you take a closer look, you will find a problem in script 2, that is, the target in the last line of script 2 is only a method name, and it is not a correct method call, the correct syntax should be followed by the target () in parentheses, as shown below:

 

# Script 3def decorator (func): func () print ('this is recorator') @ decoratordef target (): print ('this is target') target () -------------------------------------- running result: this is targetthis is decoratorTraceback (most recent call last): File "C:/Users/Me/Desktop/ff. py ", line 34, in <module> target () TypeError: 'nonetype 'object is not callable

 

As you can see, if you follow the correct syntax, you will see two lines of printed text "this is target" and "this is decorator ", the error message ff. py is the name of a py script temporarily written for writing this article, prompting that the 'nonetype 'object cannot be called. What's going on? Well, I have to tell you that script 2 and script 3 are not the correct way to use the decorator, not an error, the decorator Method Used as the decorator is not friendly. Yes, I don't think it is a wrong way of writing, but it is unfriendly. However, as long as you understand the truth, you can use the appropriate method to run normally, which is why Script 2 seems to have written a wrong call method but has obtained the correct result. Of course, the learning is still well organized. I will explain how to write the correct decorator later. Here I will explain how Script 2 and script 3 run, understanding their operating principles and causes of errors is actually understanding the principles of the decorator.

The difference between script 2 and script 3 lies in the target and target (). That is to say, the real difference lies in the brackets. When () is appended to a method or class, it indicates a call, or a running or instantiation. No matter what the name is, the essential meaning is not different. It is the object provided by the call, when an object is not callable, an error occurs: 'object of a certain type is not callable. After a method is called, that is, target (), whether a method can be executed again depends on whether it returns an object and whether the object can be called. Maybe you will be confused. Comparing the Code will make it easier to understand what I want to express:

 

 1 >>>def returnme(): 2 >>>    print('this is returnme') 3   4 >>>def target(): 5 >>>    print('this is target') 6    7 >>>target 8 <function target at 0x00000000030A40D0> 9   10 >>>target()11 target12 <function returnme at 0x00000000030A4268>13  14 >>>target()()15 target16 returnme17 18 >>>returnme()()19 returnme20 Traceback (most recent call last):21   File "<pyshell#15>", line 1, in <module>22     returnme()()23 TypeError: 'NoneType' object is not callable

 

As shown above, when you directly input target in the script, it just tells the compiler (I think it is a compiler, because I do not quite understand the so-called compiler ), in short, it is to tell the "brain" that doesn't know where to control all python code running.

0x00000000030A40D0 (this location should be the memory location) has a function (method) called target; add () after the target to call this method, that is, input target (), the "brain" runs the code written by the target method one by one, and prints the target string. The "brain" understands that there is a returnme method at 0x00000000030a00008; because the target object will return a returnme method after calling, and the method can be called, you can directly write target ()(), the "brain" will execute the code in the target one by one and return a returnme one by one. Because a () is added, the returned returnme will be called, so the code in returnme will be executed one by one, at last, we can see the printed results of 15 and 16. The returnme method does not return any callable objects. Therefore, when returnme () is input, "brain" reports an error.

The following describes the running details of script 2 and script 3. As mentioned earlier, the working principle of the decorator is as demonstrated by Script 1 code.

 

@ Decoratordef target ():... is equivalent to def decorator (target) ():... note: The preceding statements in python syntax are invalid.

 

When you call the decorator function of the decorator method target, the decorator function of the decorator is executed first. Then, the "brain" uploads the target method as a parameter, so:

 

# Script 2def decorator (func): func () print ('this is recorator') @ decoratordef target (): print ('this is target') target ------------------------------------- actual running status: first, call the decorator method: decorator () because the decorator method contains one parameter, the target is passed in: decorator (target) to run the code "func ()". Based on the input parameter, execute target () and print the result: this is target running code "print ('this is recorator')". The result is: this is decorator.

 

Compare the running status of script 3:

 

# Script 3def decorator (func): func () print ('this is recorator') @ decoratordef target (): print ('this is target') target () ----------------------------------------- actual running condition: First call the decorator method: decorator () because the decorator method contains one parameter, the target is passed in to the decorator (target) Running code "func ()", according to the input parameters, the target () is actually executed, and the result is printed: this is target running code "print ('this is recorator')". The result is printed: this is decorator and above are identical to the running conditions in script 2. The next step is to execute the () not available in target in script 2, that is, execute the call command. Because the decorator (target) does not return a callable object, the "brain" prompts an error: 'nonetype 'object is not callable

 

If you are not clear about it, see the following equivalence relationship:

 

@ Decoratordef target ():... equivalent to def decorator (target )():... therefore: target = decorator (target) target () = decorator (target) (). Therefore, if a variable var = target assigns a target value to var, in fact, the call result of decorator (target) is assigned to var, because var is not callable, so when var () is executed, the compiler reports an error. It is a NoneType object and cannot be called.

 

To sum up, you probably have been able to understand what the so-called decorator is and how it works. However, the writing method in script 2 and script 3 will bring some confusions. This confusions are after the target is decorated by the decorator modifier we have written, change target into a method that can never be called, or a method that reports an error when it is called. This is not in coordination with our usage habits and our understanding of methods. After all, we are still used to the idea that a method is naturally doomed to be called. So to satisfy our definition of the method, we 'd better write the method as a modifier into a method that can return objects with the ability to be called.

 

# Script 4def whatever (): print ('this is whatever ') def decorator (func): func () print ('this is decorator ') return whatever #1 @ decoratordef target (): print ('this is target') ---------------------------- input: target result: this is targetthis is decorator input: target () Result: this is targetthis is decoratorthis is whatever

 

At the position of #1, you can return any method or class that can be called, or even directly write it:

 

Def whatever (): print ('this is whatever ') def decorator (func): return whatever @ decoratordef target (): print ('this is target') -------------------------- input: target result: indicates that the compiler has a whatever method at a certain position in the memory. Input: target () Result: this is whatever.

 

The purpose of the above decorator is to completely convert the target method into the whatever method. However, this can only perfectly explain the efficacy of the decorator, Which is meaningless in practice. Why is the final result of the effort to write a lot of code completely calling another existing method? If you want to call the whatever method, why don't I write whatever directly in my code?

As the name suggests, a decoration device is used to modify the objects to be decorated and repackage them to achieve different effects, although it can make a decoration object invisible or directly become another object, it is not the main significance of its invention, instead, it was invented to help us write code more efficiently and concisely, decorate other methods or classes, rather than destroy them. For example, to check the received data, we only need to write a verification method, which can be used as a modifier before many other methods.

  

3. Regular decorators

 

Broadly speaking, the modifier is in script 1. Using python, you can pass parameters in a method and use one method to change another method as long as the change succeeds, can be considered as a qualified decoration device. However, this is theoretically qualified. After all, the decorator is a syntactic sugar, which should bring us convenience rather than useless work. Therefore:

 

1. the method cannot be called. It is not good: def decorator (func): func () print ('this is recorator') 2. completely eliminate the original method and directly turn it into another method. Bad: def decorator (func): return whatever3. add other functions while retaining the original method. Bad: def decorator (func ): func () print ('this is recorator') return whatever

 

In the above three writing methods, the first two are obviously bad. They simply turn the decorator into a demon. However, although it seems that the modifier method is repackaged, some commands are executed without authorization before the method is called, that is, when you enter target instead of target:

 

# Script 4def whatever (): print ('this is whatever ') def decorator (func): func () print ('this is decorator ') return whatever #1 @ decoratordef target (): print ('this is target') ---------------------------- input: target result: this is targetthis is decorator

 

You have not executed target (), but the compiler has printed two lines of strings. This is not what we want. When we write down the target in the code, we do not want the compiler to execute any command immediately. We want the compiler to execute the operation only when it encounters target. And if we don't want to return whatever, we just want to use the decorator so that the target method can print a line of "this is decorator" in addition to "this is target ", all Code contains only the target and decorator methods. What should I do if there is no other method involved?

When you ask this question, you are actually beginning to understand the meaning of the existence of the decorator. The following is a general method of decorator for solving these problems:

 

# Script 5def decorator (func): def restructure (): func () print ('this is recorator') return restructure @ decoratordef target (): print ('this is target ')

 

Yes, from the outermost layer, the above Code actually only has two methods: decorator and target -- decoring and decoring methods. However, a method restructure is embedded in the decorator, which is used to transform the target. The decorator is only responsible for transmitting the target. The restructure here is equivalent to the whatever role written outside the decorator in script 4. You can also write the effect of script 4 by using the regular method of the decorator, as shown below:

 

def decorator(func):       func()    print('this is decorator')    def whatever():        print('this is whatever')         return restructure@decoratordef target():    print('this is target')

 

Compared with the above method, you will find that the python method passing parameters is similar to the inheritance of classes. Within the decorator, you can write any Code except whatever. When executing the target, initialize the decorator, that is, the code that can be executed inside the decorator. When the target () is executed, the initialized decorator is called, therefore, decorator must return a calling object after initialization. Therefore, do not insert code in the middle of decorator and whatever unless you want to execute some code before the target method initialization.

Under normal circumstances, when the decorator completes initialization, return a callable object, that is, the restructure method in script 5. This method replaces the target clone, in the restructure, you can rewrite the target, or use other code to wrap the target. Therefore, if you only want to initialize the target (actually initialize the restructure), you should write the code you want to initialize into the restructure. In addition, you can embed multiple methods or multi-layer methods in the decorator, for example:

 

# Script 6def decorator (func): def restructure (): func () print ('this is recorator') def whatever (): func () print ('this is whatever ') return restructure @ decoratordef target (): print ('this is target ')

 

The target decorated by the decorator will finally print a line of 'this is recorator' or 'this is whatever', depending on which method (restructure or whatever) the decorator method returns ), therefore, the above Code is equivalent to the following code:

 

Executing target () is equivalent to initializing decorator (target) first. A restructure is returned, that is, target = decorator (target) = restructure. Then, call: target () = decorator (target) () = restructure () is the same as the class. After the target is passed into the decorator, as a decorator embedded method, you can call (inherit) the target method, which is why restructure can modify the target without passing parameters. Note: In python, the preceding multiple () statements are invalid. This is only for ease of understanding.

 

The decorator concept can also be designed into multiple () forms, but this destroys the basic writing method of python and is hard to understand, especially when there are multiple decorations, therefore, the design prefixed with @ is more elegant and clear.

The reason why I use multiple () statements that are not supported by python is to explain my understanding of the python decorator, it is because I believe that the syntax abandoned by python can help you better understand python's inheritance, passing parameters, and decorators, especially those with parameters.

 

4. Decorate the method with Parameters

 

First, check the following code:

 

Def target (x): print ('this is target % s' % x) def decorator (func, x): func (x) print ('this is decorator % s' % x) decorator (target ,'! ') Equivalent to: def decorator (func): def restructure (x): func (x) print ('this is decorator % s' % x) return restructure @ decoratordef target (x): print ('this is target % s' % x) target ('! ')

 

How does the parameter x in target (x) be passed in and when is it passed in to the decorator? First, try the following code:

 

Def decorator (func): print (x) # add a line of code def restructure (x): func (x) print ('this is decorator % s' % x) return restructure @ decoratordef target (x): print ('this is target % s' % x) target ('! ')

 

In this case, the compiler reports that the error parameter x is not defined. That is to say, when the decorator is initialized, only the target method is passed in. Its Parameter x = '! 'Is not passed in.

Now let's review the working principle of the previously mentioned decorator as follows:

 

Target = decorator (target) = restructure. Target () = decorator (target) () = restructure () likewise: target (x) = decorator (target) (x) = restructure (x)

 

Therefore, you can clearly understand that the target parameter is not passed to the decorator, but to the restructure of the return after the decorator initialization. Therefore, if the decorator is written as follows:

 

Def decorator (func): def restructure (): # func (x) print ('this is decorator % s' % x) return restructure

 

Enter target ('! '), The compiler will tell you that restructure has no parameters, but one parameter is passed in. The input parameter is x = '! '.

So now you understand how the decorated method target (x), method target, and parameter x are passed in, therefore, you must ensure that the restructure method of the object returned after the decorator Initialization is involved in matching the target method parameters, that is:

 

If it is defined as def target (x), In the decorator: def restructure (x), if it is defined as def target (x, y), In the decorator: def restructure (x, y)

 

You may find that if you want the decorator to decorate both target (x) and newtarget (x, y), the above statement cannot meet the requirements. Therefore, to make the decorator suitable for more objects, we 'd better write the decorator in the following format:

 

def decorator(func):    def restructure(*x):        func(*x)        print('this is decorator')    return restructure@decoratordef target(x):    print('this is target %s'%x)@decoratordef newtarget(x,y):    print('this is target %s%s'%(x,y))target('!')newtarget('!','?')

 

Using python's parameter syntax with asterisks (* arg), you can input any number of parameters. You can also set parameters with double star numbers (** arg ), the dictionary parameters can be passed in. Single-star and double-star parameters can be used at the same time, for example, def restructure (* arg, ** arg ).

 

5. decorator with Parameters

 

As long as you remember the working principle of the above decorator, you can know how to write a decorator with parameters, such:

 

Def newdecorator (I): def decorator (func): def restructure (x): func (x) print ('this is decorator % s % s' % (I, x )) return restructure return decorator @ newdecorator ('? ') Def target (x): print ('this is target % s' % x) target ('! ') ------------------------------------------------------- Result: this is target! This is decorator ?!

 

The above code is actually:

 

target(x) == newdecorator(i)(target)(x) == decorator(target)(x) == reconstructure(x)

 

Similarly, you can write newdecorator (I) As newdecorator (* I, ** ii) to satisfy different numbers of parameters ).

 

6. Conclusion

 

As long as you understand the design principles of the decorator, You can freely write out the desired decorator, even if it is a multi-parameter or multi-parameter decorator.


How should I understand the python decorator?

The so-called decorator is to wrap the function and add some additional functions for the function. The decorator is a function. The parameter is the encapsulated function and the encapsulated function is returned: You can try again:
Def d (fp): def _ d (* arg, ** karg): print "do something before fp .. "r = fp (* arg, ** karg) print" do something after fp .. "return r return _ d @ ddef f (): print" call f "# The above @ d is used to indicate the decorator and the following: # f = d (f) f () # Call f

How to Understand the instances of class objects in python programming?

Class is the generalization of a class of things, such as people.
The data type includes built-in strings, numbers, plural numbers, and other custom classes.
Objects and instances are specific things in the class, such as men, women, and others. Here men and women can also be one type, such as older men, young man.
Remember that a class is a collective term of a type of thing, and an instance (or object) is a specific thing.
For reference only.
Example:
Class Person:
'''Basic attributes of a person: name, age, and Gender '''
Def _ init _ (self, name, age, sex ):
Self. name = name
Self. age = age
Self. sex = sex

Class Man (Person ):
Def _ init _ (self, name, age ):
Super (Man, self). _ init _ (name, age, 'male ')

Class Woman (Person ):
Def _ init _ (self, name, age ):
Super (Woman, self). _ init _ (name, age, 'female ')

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.