Isaac To
Isaac To

Reputation: 739

`functools.update_wrapper` and `functools.wraps` copy more attributes over than expected

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

Answers (1)

Patrick Haugh
Patrick Haugh

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) and WRAPPER_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

Related Questions