How to use "assigned" and "updated" functools.wraps options?

I know wraps has attributes as shown below:

functools.wraps (wrapped [, assigned] [, updated])

But I want to know how to use the assigned and updated parameters, does anyone have an example?

+6
source share
1 answer

The assigned parameter indicates which attributes in the wrapper function will be assigned to the attributes with the same name in the wrapped (decorated) function. By default, they are '__module__', '__name__', '__doc__' , which are set by default in the functools.WRAPPER_ASSIGNMENTS variable. Since @abarnet puts this in a comment, one example of another attribute that could be copied would be function annotations in Python 3.x - so you might need an assigned parameter: ('__module__', '__name__', '__doc__', '__anotations__') .

The β€œupdated” parameter is more or less the same, but the corresponding attributes in the shell will have its β€œupdated” method, called with this attribute from the decorated function, which means that it works only when both attributes are mutable display - for example, a dictionary. By default, the wrapper __dict__ attribute will be updated with __dict__ wrapped, which makes the wrapper function reflected by all external attributes that can be assigned by different main decorators (decorators used before the decorator with a call to "wrap". The only possible use cases for changing the "updated" one were would change it to an empty sequence to prevent __dict__ from updating. Otherwise, if you want to update more attributes, it would mean that you would work on hell is a project that will use different dictionary attributes for the called objects, and you will probably have more problems at this point than not knowing how to use the "wraps" correctly.

TL DR: you can find something for something:

 @wraps(func, ('__module__', '__name__', '__doc__', '__anotations__'), ()) def wrapper(*args, **kw): ... 

But not necessarily.

As a final, noteworthy note, if a decorated object is an instance of a class with the __call__ method, instead of a function, updating __dict__ will make the wrapper function a copy of all the attributes of the instance of the decorated instance - this is more of a side effect than a useful thing, since these copied attributes will not follow further state changes in the decorated instance (and the methods of the decorated instance will still receive the β€œI” as an expanded instance):

 >>> from functools import wraps >>> class MyCallable(object): ... def pr(self): ... print(self.a) ... def __call__(self, new_a): ... self.a = new_a >>> def deco(clb): ... @wraps(clb) ... def wrapper(*args): ... return clb(*args) ... return wrapper ... >>> m = MyCallable() >>> m(1) >>> ma 1 >>> m.pr() 1 >>> m = deco(m) >>> m(2) >>> ma 1 >>> m.__wrapped__.pr() 2 

So, this may be an example that you do not want to copy __dict__ on top of the wrapper and always access the orignal instance through the __wrapped__ attribute, as described above. But I’m really distracted, since I never saw anyone wrapping class instances with decorators and could not come up with such an opportunity that would not be better solved by a class method that does what the decorator should do first .

+3
source

Source: https://habr.com/ru/post/986198/


All Articles