Original Address 77170585
In short, the Python adorner is a function that extends the function of the original function, which is special because its return value is also a function, the advantage of using the Python adorner is to add new functionality to the function without changing the code of the original function.
In general, if we want to expand the original function code, the most straightforward way is to hack the code inside the changes, such as:
Import Time def func (): Print ("hello") time.sleep (1) print(" World ")
This is our most primitive function, and then we try to record the total time that the function executes, and the simplest thing to do is:
#primitive intrusion, tampering with the original functionImport Timedeffunc (): StartTime=time.time ()Print("Hello") Time.sleep (1) Print(" World") EndTime=time.time () msecs= (endtime-starttime) *1000Print("Time is %d Ms"%MSECS)
But if your boss in the company and you said: "Little Qi, this code is our company's core code, you can not directly change our core code." "What should we do, we'll try to write it ourselves:
#avoid direct intrusion into the original function modification, but will need to execute the function againImport TimedefDeco (func): StartTime=time.time () func () EndTime=time.time () msecs= (endtime-starttime) *1000Print("Time is %d Ms"%msecs)deffunc ():Print("Hello") Time.sleep (1) Print(" World")if __name__=='__main__': F=func deco (f)#only if func () or F () is executed as a parameter, the new join function will take effect. Print("f.__name__ is"F.__name__)#the name of F is func () Print() #func ()
Here we define a function Deco, whose parameters are a function, and then embed the timer function into the function. Then you can clap your chest and say to the boss, see, don't move your original code, I also expanded its function function.
Then your boss has said to you: "Little Qi, our company core code area has 10 million func () function, from FUNC01 () to func1kw (), according to your plan, want to expand these 10 million function function, is to perform 10 million Times Deco () function, this can not Ah, I love my machine. ”
Well, you finally have enough of your boss, ready to resign, and then you overheard the decorator this artifact, suddenly found to meet your Dr Yan's request.
We first implement a rudimentary decorator, without using any syntactic sugar and advanced syntax, to see the most primitive appearance of the adorner:
#neither need to be intrusive nor do the functions repeatImport TimedefDeco (func):defwrapper (): StartTime=time.time () func () EndTime=time.time () msecs= (endtime-starttime) *1000Print("Time is %d Ms"%msecs)returnWrapper@decodeffunc ():Print("Hello") Time.sleep (1) Print(" World")if __name__=='__main__': F= Func#here F is assigned func, and execution F () is the Execute func ()F ()
The Deco function here is the most primitive decorator, whose argument is a function, and then the return value is also a function. The function func (), which acts as a parameter, is executed inside the return function wrapper (). Then adding the @deco,func () function in front of the function func () is equivalent to being injected with the timing function, and now, as long as the Func () is called, it has become a "new function more" function.
So here the decorator is like an injection symbol: with it, extending the functionality of the original function does not require the intrusion function to change the code, do not need to repeat the original function.
#Adorner with ParametersImport TimedefDeco (func):defWrapper (A, B): StartTime=time.time () func (A, b) endTime=time.time () msecs= (endtime-starttime) *1000Print("Time is %d Ms"%msecs)returnWrapper@decodeffunc (A, b):Print("Hello,here is a func for add:") Time.sleep (1) Print("result is%d"% (A +b))if __name__=='__main__': F=func F (3,4) #func ()
Then you meet the boss's requirements, boss said: "Small qi, I let you expand the function of a lot of parameters ah, some parameters or the number of the kind, your decorator do not make it?" "Then you hehe smile, deep work and name!"
#adorners with indeterminate parametersImport TimedefDeco (func):defWrapper (*args, * *Kwargs): StartTime=time.time () func (*args, * *Kwargs) EndTime=time.time () msecs= (endtime-starttime) *1000Print("Time is %d Ms"%msecs)returnWrapper@decodeffunc (A, b):Print("Hello,here is a func for add:") Time.sleep (1) Print("result is%d"% (A +b)) @decodefFunc2 (a,b,c):Print("Hello,here is a func for add:") Time.sleep (1) Print("result is%d"% (a+b+c))if __name__=='__main__': F=func Func2 (3,4,5) F (3,4) #func ()
Finally, your boss said: "Yes, little qi, I have a function here need to add a lot of functions, a decorator is afraid, the adorner can support a number of it"
In the end you throw this piece of code at him:
#multiple adornersImport Timedefdeco01 (func):defWrapper (*args, * *Kwargs):Print("This is deco01") StartTime=time.time () func (*args, * *Kwargs) EndTime=time.time () msecs= (endtime-starttime) *1000Print("Time is %d Ms"%msecs)Print("Deco01 End Here") returnwrapperdefdeco02 (func):defWrapper (*args, * *Kwargs):Print("This is deco02") func (*args, * *Kwargs)Print("Deco02 End Here") returnwrapper@deco01@deco02deffunc (A, b):Print("Hello,here is a func for add:") Time.sleep (1) Print("result is%d"% (A +b))if __name__=='__main__': F=func F (3,4) #func ()" "This is Deco01this is Deco02hello,here are a func for Add:result are 7deco02 end heretime is 1003 msdeco01 end HERE" "
The order in which multiple adorners are executed starts with the last adorner, executes to the first adorner, and executes the function itself.
An example of a child's shoe in a stolen comment:
defDEC1 (func):Print("1111") defOne ():Print("2222") func ()Print("3333") return OnedefDEC2 (func):Print("AAAA") defBoth ():Print("bbbb") func ()Print("CCCC") return@dec1 @dec2defTest ():Print("test test") test ()
Output:
AAAA 1111 2222 bbbb test test cccc 3333
Adorner call order
Adorners can be used overlay, then this is related to the adorner call order. For the "@" syntax sugar in Python, the adorner is called in the opposite order of the use of the @ syntax sugar declaration.
In this example, Addfunc (3, 8) = Deco_1 (Deco_2 (Addfunc (3, 8)).
Reference: Python Decorator: http://python.jobbole.com/82344/
Python decorator detailed