Metadata Preservation with functools.wraps
1Concept
When a decorator wraps a function, the function's name (`__name__`), docstring (`__doc__`), and annotations are overwritten by the wrapper function. Decorating the wrapper with `@functools.wraps(func)` copies the original metadata, preserving introspection and debugger capabilities.
2Architecture Diagram
Without @wraps: func.__name__ becomes 'wrapper' (Breaks Sphinx docs & debuggers!) With @wraps: func.__name__ remains original 'process_payment'
3Code Example
Python 3.12
from functools import wraps
def audit_log(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Auditing execution of: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@audit_log
def transfer_funds(amount: float) -> str:
'''Transfers funds securely between bank accounts.'''
return f"${amount} transferred"
print(f"Function Name: {transfer_funds.__name__}")
print(f"Docstring: {transfer_funds.__doc__}")4Expected Output
Function Name: transfer_funds Docstring: Transfers funds securely between bank accounts.
5Key Takeaways
- ✓Always apply `@wraps(func)` to inner wrapper functions.
- ✓Preserves `__wrapped__` attribute for accessing the original undecorated function.
- ✓Essential for frameworks like FastAPI and Sphinx that rely on signature introspection.