Phase 5 of 25 · Topic 5.2

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.