Reputation: 739
I used functools.wraps
in a definition of a decorator to forward some attributes of a function to its wrapper. According to the documentation of functools.wraps
, which is based on functools.update_wrapper
, functools.wraps
should assign the attributes, __module__
, __name__
, __qualname__
, __annotations__
, and __doc__
, of the wrapped function to its wrapper by default. However, in my own usage, I see that functools.wraps
forwards whatever attribute I define in the wrapped function as well.
import functools
def decorator(func):
func.added_attr = 'I am added.'
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@decorator
def foo():
pass
print(foo.added_attr)
In the example above, foo
eventually references the wrapper defined in decorator
, yet this wrapper also has the added_attr
defined in wrapped function. Can anyone explain this behavior which is not mention in the documentation?
Note: I tested the code above in Python 3.7 and 3.8.
Upvotes: 0
Views: 483
Reputation: 61014
From the update_wrapper
docs (emphasis mine):
The default values for these arguments are the module level constants
WRAPPER_ASSIGNMENTS
(which assigns to the wrapper function’s__module__
,__name__
,__qualname__
,__annotations__
and__doc__
, the documentation string) andWRAPPER_UPDATES
(which updates the wrapper function’s__dict__
, i.e. the instance dictionary).
func.added_attr = 'I am added.'
updates func.__dict__
, which gets copied over by update_wrapper
Upvotes: 2