The functools.wraps decorator allows you to keep your function’s identity intact after
it’s been wrapped by a decorator. Whenever a function is wrapped by a decorator, identity
properties like - function name, docstring, annotations of it get replaced by those of the
wrapper function. Consider this example:
from __future__ import annotations
# In < Python 3.9, import this from the typing module.
from collections.abc import Callable
from typing import Any
def log(func: Callable) -> Callable:
def wrapper(*args: Any, **kwargs: Any) -> Any:
"""Internal wrapper."""
val = func(*args, **kwargs)
return val
return wrapper
@log
def add(x: int, y: int) -> int:
"""Add two numbers.
Parameters
----------
x : int
First argument.
y : int
Second argument.
Returns
-------
int
Returns the summation of two integers.
"""
return x + y
if __name__ == "__main__":
print(add.__doc__)
print(add.__name__)
Here, I’ve defined a simple logging decorator that wraps the add function. The function
add has its own type annotations and docstring. So, you’d expect the docstring and
name of the add function to be printed when the above snippet gets executed. However,
running the script prints the following instead: