Python Automation Development Learning 4-decorators

Source: Internet
Author: User
Tags sleep function

Decorative Device

An adorner lets you add additional functionality to a function. Adding functionality can be achieved by modifying the function itself, but there are 2 benefits of using adorners. 2 Principles of adorners:

    1. Do not change the source code of the decorated function

    2. Does not change the way the decorated function is called

Following the 2 principles above, we can add additional functionality to the function without destroying the existing stable code and code invocation methods. and easy fallback.

Define a function First:

Import Timedef Sleep (): "Wait 2 seconds after running" print ("Wait for 2 Seconds") Time.sleep (2) print ("END") sleep ()

Now I want to add a function to this function to calculate the time the function is running, but I don't want to modify the source code of the sleep function, so we define a function to attach this function.

Import Timedef Sub_a (func): "Run time of function calculating parameters" T = Time.time () # Record current timestamp func () print (Time.time ()-T) # now timestamp and The difference between the previous timestamp is the run time of this function, Def sleep (): "Wait 2 seconds after running" print ("Wait for 2 Seconds") Time.sleep (2) print ("END") sub_a (Slee P

Instead of modifying the sleep function, we define a new function. The additional code is executed with this new function and the decorated function is executed with a parameter call.

But here we have changed the way it is called, and now we need to invoke the new function and call it using the original invocation method, sleep ().

On the basis of the previous, we put a layer of function on the outside of the adorner. Look at the code first, and then analyze the implementation process.

Import Timedef Sub_b (func): Def sub_a (): "Run time of function calculating parameters" T = Time.time () func () print (time.t     IME ()-T) return Sub_a # Returns the memory address of the SUB_A function Def sleep (): "Wait 2 seconds after running" print ("Wait for 2 Seconds") Time.sleep (2) Print ("END") sleep = Sub_b (sleep) sleep ()

After the sleep = Sub_b (sleep) statement is assigned, the value of sleep is the return value of the Sub_b function, which is the memory address of sub_a, and the Func in Sub_a has already assigned the memory address of sleep (in the call sub_ b When the memory address of sleep is passed in as a parameter).

Finally we sleep () the actual call is Sub_a (), while the Func () in sub_a executes sleep (). The additional code and the sleep source code are executed, and the last call is not changed.

Here again to explain a small problem, sub_a is now just a sub-function in the Sub_b function, local variables. That is, the Sub_a will be released after the call is finished sub_b.

But since Sub_b's last return sub_a returns the memory address of sub_a, and in Sleep=sub_b (sleep), the memory address is assigned to sleep. So at the end of the Sub_b call, Sub_a was still occupied by sleep, so it didn't release sub_a.

The principle of not changing the calling method is also realized.

Take a look at the arguments, the previous function has no parameters, and if you add a parameter to the sleep () function, the code will error. So the present decorator can only decorate functions without parameters, to adapt to the functions of various parameter types, we need to use the invariant parameters

Import Timedef Sub_b (func): Def sub_a (*args,**kwargs): # There's no brains here plus no fixed parameter "run time of function to calculate parameters" T = Time.time ()    Func (*args,**kwargs) # passes all parameters to the Decorated function print (time.time ()-T) return sub_adef sleep (n): # Now let's change a function with parameters to decorate it "Wait n seconds after run" print ("Wait for%d Seconds"%n) time.sleep (n) Print ("END") sleep = Sub_b (Sleep) sleep (2)

Simple without the brain plus not fixed parameters on the line, specifically what parameters, the specific number of parameters we do not care, as long as the whole pass through the line.

As such, the parameters are not a problem. There is also a problem with the return value, which modifies sleep to a function that has a return value. There will be problems, this time no error, but the return value is none.

Again, when the call is decorated, the return value is saved. The adorner finally return this value to the adorner.

Import Timedef Sub_b (func): Def sub_a (*args,**kwargs): "Run time of function calculating parameters" T = time.time () res = func (* Args,**kwargs) # will be saved by the return value of the Adornment function print (Time.time ()-T) return Res # Returns the previously saved value here as the adorner return value return Sub_ade F Sleep (N): "Wait n seconds after run" print ("Wait for%d Seconds"%n) Time.sleep (n) return "END" sleep = Sub_b (sleep) print (Slee P (2))

The return value is now also available. Everything is full, but there is a little bit different from other people's decorators. Two sentences. Someone else's decorator probably looks like this.

Import Timedef Sub_b (func): Def sub_a (*args,**kwargs): "Run time of function calculating parameters" T = time.time () res = func (*    Args,**kwargs) Print (Time.time ()-T) return res return Sub_a@sub_b # Add this sentence def sleep (n): "Wait n seconds after running" Print ("Wait for%d Seconds"%n) Time.sleep (n) return "END" #sleep = Sub_b (sleep) # remove this sentence print (Sleep (2))

The @ statement is used here and is placed in front of the decorated function. Replaces the assignment statement that was originally behind the decorated function. The effect of the two sentences is the same.

But the @ statement is significantly more concise and the position is easier to read before being decorated.

However, we will continue to use the form of assignment later, and I feel better understanding how adorners are implemented.

The adorner is actually a function, then the function can take parameters, through the parameters, you can make the function have more options. Now we're going to add the parameters to the adorner as well.

We set a layer for the adorner before the implementation does not change the invocation mode. Now in order to let the adorner can take the parameters, we need to set another layer, the specific principle is not very clear, first look at the three layer of code:

Import timedef sub_c ():  #  not write the parameters, the future parameters can be filled here     def sub_b ( Func):         def sub_a (*args,**kwargs):              "Run time for functions that calculate parameters"              t = time.time ()              res = func (*args,**kwargs)              print (Time.time ()  - t)              return res        return sub_a     Return sub_bdef sleep (n):     "Wait n seconds after Run"     print ("wait  For %d seconds "%n)     time.sleep (n)      return " END "Sleep =&nbsP;sub_c () (sleep) print (Sleep (2)) 

First look at the meaning of the assignment, Sleep=sub_c () (sleep). The value of Sub_c () is his return value Sub_b, which is the memory address of the Sub_b function. The back is followed (sleep), which is the execution of Sub_b (sleep). That is to say Sleep=sub_b (sleep). So stripped the outermost layer, just like the above two layers of assignment.

So in the three-layer decorator, there is one more () behind the Sub_c, because here we want the return value of the outermost function. In the case of a two-layer decorator, there is no () behind it, which is the memory address of the function code block.

Finally, we can easily bring the parameters for the adorner. We add parameters that control the number of floating-point decimal digits.

Import timedef sub_c (N):     def sub_b (func):         def sub_a (*args,**kwargs):              "Run time of function to calculate parameters"             t =  time.time ()             res = func ( *args,**kwargs)             print (Round (Time.time ( ) ( - t), N)             return res         return sub_a    return sub_bdef  sleep (n):     "Wait n seconds after Run"     print ("wait for %d  Seconds "%n)     time.sleep (n)      return " END "sleep =  sub_c (8) (Sleep) print (Sleep (2)) 

And finally, in the form of @

Summarize

Finally, 2 of the final template of the adorner, according to the following adjustment, even if not understand should also be applied.

    1. Change the outermost function name to the name of your decorator and give your decorator a proper name.

    2. The function name of the inner layer doesn't matter.

    3. The inner code block is replaced with your own code, RES=FUNC (*args,**kwargs) and the last return res are not modified

Two-layer Adorner template:

Import Timedef Run_time (func): # The outermost function name is replaced by your decorator's name Def wrapper (*args,**kwargs): "Run time of the function that calculates the parameter" T = times. Time () # Replace here with your code snippet res = func (*args,**kwargs) # This sentence is invariant print (Time.time ()-T) # Here's your code snippet return re S # This sentence does not change return wrapper@run_timedef sleep (n): "Wait n seconds after run" print ("Wait for%d Seconds"%n) time.sleep (n) retu RN "END" Print (Sleep (2))

Three-layer Adorner template:

Import timedef run_time (n):  #  the outermost function name for the name of your decorator     def  Decorator (func):  #  the function name of the inner layer does not matter         def wrapper ( *args,**kwargs):             "Run time of function to calculate parameters"              t = time.time ()   #  Replace this here with your code snippet             res = func (*args,* *kwargs)   #  This sentence unchanged             print ( Round ((Time.time ()  - t), N))   #  here to replace your code snippet              return res  #  This sentence is unchanged          return wrapper    return decorator@run_time (8) def sleep (n):      "post-operation etc.Wait n Seconds "    print (" Wait for %d seconds "%n)     time.sleep (n)      return  "END" Print (Sleep (2))


Python Automation Development Learning 4-decorators

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.