implementation of a requirement
Currently, we have a small requirement: To calculate the time of the function execution through the adorner
Calculate the execution duration of this function
def add (x, y): # add = Timeit (add) time.sleep (1) ' This is add ' return x + y
Adorner implementation
import timeimport datetimefrom functools import wrapsclass timeit: def __init__ (SELF,FN): print (' init ')        SELF._FN = FN    DEF __CALL__ ( Self, *args, **kwargs): start = Datetime.datetime.now () ret = self._fn (*args, ** Kwargs) delta = datetime.datetime.now () - Start print (Delta) return ret@timeitdef add (x, y): # add = timeit (ADD) time.sleep (1) ' This is add ' return x + yadd (print) (add.__doc__) print (add.__name__)
The information we see is as follows:
Traceback (most recent): File "h:/python_project/test2/3.py", line <module> print (add.__name__) Attributeerror: ' Timeit ' object has no attribute ' __name__ '
So the problem is that when printing __doc__ and __name__ we see that the return is not what we want, because it has been packaged into a callable object in the Timeit, so now it is an instance, and the instance is not called __name__; so let's do a manual simulation, Disguise it to write __doc__ and __name__
Reform
Manual copy: Coarse modification, __doc__ __name__ forcibly copied into the instance
Self is nothing more than an instance of the class we are currently bound to, and FN is passed in by the adorner, and we assign FN's doc and name as the source forcibly to the self, as follows:
Class Timeit:def __init__ (SELF,FN): Print (' init ') Self._fn = doc copy of fn# function to fn self.__doc__ = SE lf._fn.__doc__ self.__name__ = self._fn.__name__
This effect is certainly not good, this is to know where to save the location, then the next introduction of the wraps module
Introduction of Wraps
Wraps essence is a function decorator, by receiving a parameter to receive a parameter to pass and processing, anyway, the web is also a bunch of use methods, examples are no longer explained, but here need to call the equivalent of the function to find out
How to use:
From Functools import wrapsdef Looger (FN): @wraps (FN) def wrapper (*args, **kwargs): xxxxxxxx
Equivalence relationship: @wraps (fn) = (A = wraps (FN); A (wrapper))
As can be seen, the source is passed in FN, the goal is self, that is wrapper
Process Analysis
First we follow through the editor to the inside of the function
Def wraps (Wrapped, assigned = wrapper_assignments, updated = wrapper_updates): "" " Decorator factory to apply update_wrapper () to a wrapper function returns a decorator that invokes update_ Wrapper () with the decorated function as the wrapper argument and the arguments to wraps () as the remaining arguments. default arguments are as for update_wrapper () . this is a convenience Function to simplify applying partial () to Update_wrapper (). &NBSP;&NBSP;&Nbsp; "" "
Can see wraps, need to pass a few parameters, follow up to assigned, the function is wrapped is the SRC source, that is, the external update out
View assigned = Wrapper_assignments
Through wrapper_assignments discovery was jumped to the
Wrapper_assignments = (' __module__ ', ' __name__ ', ' __qualname__ ', ' __doc__ ', ' __annotations__ ') Wrappe R_updates = (' __dict__ ',) def update_wrapper (wrapper, wrapped, assigned = Wrapper_assig nments, updated = wrapper_updates):
can see wraps, need to pass several parameters, follow up to assigned, the wrapped function is the SRC source, that is, the external update out
View assigned = wrapper_assignments
So what does the assignment update? These properties are as follows
Wrapper_assignments = (' __module__ ', ' __name__ ', ' __qualname__ ', ' __doc__ ',
& nbsp ' __annotations__ ')
and updated = Wrapper_updates is covered by the Wrap Per_updates = (' __dict__ ',) is performed on the basis of the update operation Wrapper_assignments, and plainly all is done in the current __dict__
If there is a dictionary and such properties to do is not to overwrite the dictionary, Instead of overwriting or adding their own information in their dictionaries.
assigned only default, but enough for us to use
Object Properties Access
continue to view the code:
For attr in Assigned:
Try
Value = GetAttr (wrapped, attr)
Except Attributeerror:
Pass
Else
SetAttr (wrapper, attr, value)
For attr in updated:
GetAttr (wrapper, attr). Update (GetAttr (wrapped, attr, {}))
# Issue #17482: Set __wrapped__ last so we don ' t inadvertently copy it
# from the wrapped function when updating __dict__
wrapper.__wrapped__ = Wrapped
# Return The wrapper so this can be used as a decorator via partial ()
Return wrapper
It is through the reflection mechanism to find the __dict__, if present, to return without triggering setattr to write value to __dict__
Value = GetAttr (wrapped, attr) Gets the property from attr reflection, attr is assigent, and assigent is wrapper_assignments defined property
SetAttr (wrapper, attr, value) is dynamically added to its dictionary if it is not found
WRAPPER.__WRAPPED__ = Wrapped adds a property to the wrapper after it has been added, and it also belongs to a function enhancement, the wrapperd is the wrapper function, the Add reference is given to the Def wrapper (*args, **kwar GS); Everything that has been packaged increases this attribute.
plainly wraps is called the Update_wrapper, but less a layer of transmission
Then go back to the wraps (why can't I get the format? )
def wraps (wrapped,
Assigned = Wrapper_assignments,
Updated = wrapper_updates):
Did you feel something missing? Actually it is called the partial partial function
Return partial (Update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
Through the partial function, update_wrapper the corresponding wrapper, feeds into a function, other orders
Next, a new function is introduced, and the partial specific analysis is later written
In short a word: Wraps is passed and enhanced by means of an adorner, which will require some underlying properties to be reflected from the source to the current dict, and use a partial function to generate a new function and return
Python wraps that little thing.