functools.wraps is a decorator for wrapper functions. It copies metadata from the original function onto the wrapper (__name__, __doc__, __module__, __annotations__, and more) and sets __wrapped__ so introspection can reach the original.
Without wraps, decorated functions look like wrapper, which breaks docs, debugging, and some libraries.
from functools import wraps
def noisy(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
print(f"calling {fn.__name__}")
return fn(*args, **kwargs)
return wrapper
@noisy
def add(a, b):
"""Add two numbers."""
return a + b
print(add.__name__) # add (not wrapper)
print(add.__doc__) # Add two numbers.
print(add(2, 3))
print(add.__wrapped__(2, 3)) # originalInterview tip: Always mention @wraps(fn) when writing decorator examples; interviewers look for that habit.