Home >Backend Development >Python Tutorial >functools.wraps decorator

functools.wraps decorator

高洛峰
高洛峰Original
2016-11-05 14:11:191114browse

wraps actually have no practical use. They are used to solve the problem of changes in the properties of the function pointed to by the original function name caused by the decorator;

The decorator has decorated the function func. At this time, func does not point to the real func, but Points to the decorated function in the decorator

import sys

debug_log = sys.stderr

def trace(func):
        if debug_log:
                def callf(*args, **kwargs):
                        """A wrapper function."""
                        debug_log.write('Calling function: {}\n'.format(func.__name__))
                        res = func(*args, **kwargs)
                        debug_log.write('Return value: {}\n'.format(res))
                        return res
                return callf
        else:
                return func

@trace
def square(x):
        """Calculate the square of the given number."""
        return x * x

The square here actually points to calls. You can use help(square) or square.__name__ to check it out.

The decorated function of square is actually another function (function attributes such as function name will change)

If you use wraps for decoration

def trace(func):
        if debug_log:
          @functools.wraps(func)
                def callf(*args, **kwargs):
                        """A wrapper function."""
                        debug_log.write('Calling function: {}\n'.format(func.__name__))
                        res = func(*args, **kwargs)
                        debug_log.write('Return value: {}\n'.format(res))
                        return res
                return callf
        else:
                return func

At this time, the attributes of square decorated with trace will not change Now, you can help(square) to see

Reason: We translate the wraps decoration code as follows, and its equivalent is:

def trace(func):
        if debug_log:
                def _callf(*args, **kwargs):
                        """A wrapper function."""
                        debug_log.write('Calling function: {}\n'.format(func.__name__))
                        res = func(*args, **kwargs)
                        debug_log.write('Return value: {}\n'.format(res))
                        return res

                callf = functools.update_wrapper(_callf, wrapped = func,assigned = functools.WRAPPER_ASSIGNMENTS,updated = functools.WRAPPER_UPDATES)

                return callf
        else:
                return func

update_wrapper does a very simple job, which is a function object represented by the parameter wrapped (for example: square ) some attributes (such as: __name__, __doc__) override these corresponding attributes of the function object represented by the parameter wrapper (for example: callf, where callf simply calls the square function, so it can be said that callf is a wrapper function of square).

Therefore, after using the wraps decorator to "decorate" callf in this example, the __doc__, __name__ and other attributes of callf are exactly the same as those of the function square to be "decorated" by trace.


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn