Wrapping any function: *args, **kwargs and functools.wraps
Real decorators must work with any signature. The Unpacking series showed how *args and **kwargs collect arbitrary arguments. This lesson plugs them into a wrapper, then uses functools.wraps to keep the original function's name.
The decorators in the previous lesson only worked on functions with no arguments. Real code has functions with positional and keyword arguments.
A decorator that only handles wrapper() will break the moment the wrapped function takes arguments:
The wrapper accepted no arguments. The Unpacking series showed *args and **kwargs collect any positional and keyword arguments. Use them in both the wrapper signature and the call to func.
A wrapper that forwards everything:
What will be the output?
Forwarding *args and **kwargs is the standard pattern. Use it for any decorator unless you have a strong reason not to.
What will be the output?
There is one downside. After decorating, the function loses its identity. Its name and docstring become those of the wrapper.
Look at the function name after decorating:
Use functools.wraps to copy the original function metadata onto the wrapper. Apply it as a decorator inside your decorator.
Same code, with @wraps(func):
What will be the output?
What will be the output?
What will be the output?
What will be the output?