Transferred from: http://www.cnblogs.com/xybaby/p/6274187.html
Generally speaking
An adorner is a function that takes a function (or class) as a parameter, and the return value is also a function (or class)。 Let's start with a simple example:
#-*-coding:utf-8-*-2def log_cost_time (func):3def wrapped (*args, * *Kwargs):4Import Time5Begin =time.time ()6 Try: 7 returnFunc (*args, * *Kwargs)8 finally: 9Print'func%s cost%s'% (func.__name__, time.time ()-begin)Ten returnWrapped One A@log_cost_time -def complex_func (num): -RET =0 the forIinchxrange (num): -RET + = i *I - returnret -#complex_func =log_cost_time (Complex_func) + - if__name__ = ='__main__': +Print Complex_func (100000) Copy the code
View Code
In the code, the function log_cost_time is an adorner, its function is also very simple, printing is decorated function run time.
The adorner's syntax is as follows:
1 @dec 2 def func ():p
is essentially equivalent to: func = Dec (func).
In the code snippet 0 above, the Line12 is commented out and then the line18 annotation is removed, which is the same effect. In addition, Staticmethod and Classmethod are two adorners that we often used in the code, and if the PYC is deserialized, the resulting code is generally the Func = Staticmthod (func) pattern. Of course, the @ symbol is more popular in the form of at least one less spelling of the function name.
adorners can be nested, such as @dec0 @dec1 def func ():p, and so will be in Func = DEC0 (DEC1 (fun)). Adorners also have "side effects", for the Complex_calc decorated by log_cost_time, we look at complex_func.__name__, the output is: "Wrapped" ". Well, this is the name of inner function (wrapped) inside the log_cost_time, and of course the caller wants the output to be "Complex_func", in order to solve this problem, Python provides two functions.
Prototype:
functools.
update_wrapper(
Wrapper, wrapped[, assigned][, updated]The third parameter, copy the value of wrapped directly to wrapper, default to (__doc__, __name__, __module__) fourth parameter, update, default = (__dict__)
- Package of Functools.wraps:update_wrapper
is for Partial as a function decorator when defining a wrapper function.
Simple Change Code:
1 Import Functools2 def log_cost_time (func):3 @functools. Wraps (func)4def wrapped (*args, * *Kwargs):5 Import Time6Begin =time.time ()7 Try:8 returnFunc (*args, * *Kwargs)9 finally:TenPrint'func%s cost%s'% (func.__name__, time.time ()-begin) One returnWrapped
And look at the complex_func.__name__ output is "Complex_func"
adorners are also available with parameters.。 Let's modify the above code slightly:
1 def log_cost_time (stream):2 def Inner_dec (func):3def wrapped (*args, * *Kwargs):4 Import Time5Begin =time.time ()6 Try:7 returnFunc (*args, * *Kwargs)8 finally:9Stream.Write ('func%s cost%s \ n'% (func.__name__, time.time ()-begin))Ten returnWrapped One returnInner_dec A - Import SYS - @log_cost_time (sys.stdout) the def complex_func (num): -RET =0 - forIinchxrange (num): -RET + = i *I + returnret - + if__name__ = ='__main__': APrint Complex_func (100000)
The Log_cost_time function also accepts a parameter that specifies the output stream for the information, for decorator with parameters
@dec (Dec_args) def func (*args, **kwargs):p is equivalent to Func = Dec (Dec_args) (*args, **kwargs).
Decorator's modification of a classis also very simple, but usually not used much. For example, we need to change the __str__ method of the class, the code is very simple.
1 def Haha (CLZ):2clz.__str__ = lambda s:"Haha"3 returnCLZ4 5 @Haha6 classWidgets (Object):7 " "class Widget" "8 9 if__name__ = ='__main__':TenW =widgets () OnePrint W
It is necessary to use decorator in any scenario, and a pattern in design mode is also called an adorner. Let's briefly review the adorner pattern in the design pattern, a simple sentence overview
Dynamically add additional responsibility to an object
Because the adorner mode only changes the component externally, the component does not need to have any knowledge of its decorations, which means that the decorations are transparent to the component.
Returning to Python, it is natural to implement the adorner pattern with the decorator syntax, such as the sample code in this article, which adds extra functionality to record function execution time without changing the decorated object. Of course, because of the flexibility of the Python language, decorator can modify objects that are decorated (such as examples of decorative classes). Decorator is very versatile in Python, here are a few things:
(1) Modify the properties or behavior of the decorated object (2) Handle the context that is executed by the function object, such as setting environment variables, plus log and so on (3) to handle the repetitive logic, such as n functions can run out of the exception, but we do not care about these exceptions, as long as the caller does not pass the exception to the line At this point, you can write a catchall decorator for the function that might run out of the exception.
def catchall (func): @functools. Wraps (func) def wrapped (*args, * *Kwargs) :Try : return func (*args, * *Kwargs) except: pass return Wrapped
Functional programming of the REFERENCESPEP 0318:https://www.python.org/dev/peps/pep-0318/#syntax-alternativespython modifier:/http Coolshell.cn/articles/11265.html
Python Decorator Basics