Decorators

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:

Python
Output

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:

Python
Output

What will be the output?

Python

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?

Python

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:

Python
Output

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):

Python
Output

What will be the output?

Python

What will be the output?

Python

What will be the output?

Python

What will be the output?

Python