Why is functools.wraps necessary when writing decorators?
Without functools.wraps, the wrapper function replaces the original's __name__, __doc__, __module__, __qualname__, and __annotations__, breaking introspection, logging, and documentation tools. functools.wraps copies all of these attributes from the wrapped function to the wrapper and stores a reference in __wrapped__ for unwrapping.
How to think about it
What this question is really testing
Decorators are everywhere in Python frameworks. The interviewer wants to see that you don’t just know how to write a decorator — you know the production pitfall that trips up most people: without @functools.wraps, the wrapper silently stomps on the original function’s identity, breaking logging, routing frameworks, test fixtures, and documentation tools.
The problem: identity theft
A naive wrapper replaces the original function’s metadata:
def timer(func):
def wrapper(*args, **kwargs): # no @wraps
return func(*args, **kwargs)
return wrapper
@timer
def train(epochs):
"""Train the model for a given number of epochs."""
...
print(train.__name__) # 'wrapper' — wrong
print(train.__doc__) # None — documentation gone
This breaks Flask/FastAPI route naming, pytest fixture discovery, Sphinx docs, and any logging that uses func.__name__.
The fix: @functools.wraps
What functools.wraps copies
@functools.wraps(func) is a shorthand for calling functools.update_wrapper(wrapper, func), which copies:
| Attribute | Why it matters |
|---|---|
__name__ | Flask/FastAPI routes, logging, pytest fixtures |
__doc__ | Sphinx, help(), IDE hover docs |
__module__ | Correct module attribution |
__qualname__ | Accurate stack traces |
__annotations__ | Type checkers, FastAPI request parsing |
__wrapped__ | Allows inspect.unwrap to peel back layers |
The key insight
The __wrapped__ attribute is especially valuable: it lets inspect.unwrap traverse an entire decorator stack to reach the original function. This is how testing tools can access the undecorated function signature, and how debuggers show you meaningful stack traces instead of a tower of wrapper frames.