Peeking into the internals of Python's 'functools.wraps' decorator
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: ...