Python wraps that little thing.

Source: Internet
Author: User
Tags wrapper

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.

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.