Understanding the Problem
When creating decorators, a common issue arises with metadata preservation. Without proper handling, decorated functions lose their original metadata such as name, docstring, and other attributes.
functools.wraps is a decorator designed to solve metadata preservation problems when creating custom decorators.
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Wrapper function documentation"""
return func(*args, **kwargs)
return wrapper
graph TD
A[Without wraps] --> B[Loses Original Metadata]
C[With wraps] --> D[Preserves Original Metadata]
Practical Example
import functools
def without_wraps(func):
def wrapper(*args, **kwargs):
"""Wrapper function"""
return func(*args, **kwargs)
return wrapper
def with_wraps(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
"""Wrapper function"""
return func(*args, **kwargs)
return wrapper
@without_wraps
def original_function():
"""Original function documentation"""
pass
@with_wraps
def wrapped_function():
"""Original function documentation"""
pass
## Metadata Comparison
print("Without wraps:")
print(without_wraps.__name__)
print(without_wraps.__doc__)
print("\nWith wraps:")
print(with_wraps.__name__)
print(with_wraps.__doc__)
| Benefit |
Description |
| Metadata Preservation |
Keeps original function's metadata |
| Debugging Support |
Improves debugging and introspection |
| Consistent Function Representation |
Maintains function's original identity |
Advanced Use Cases
Multiple Decorators
def decorator1(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Decorator 1")
return func(*args, **kwargs)
return wrapper
def decorator2(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("Decorator 2")
return func(*args, **kwargs)
return wrapper
@decorator1
@decorator2
def combined_function():
"""Function with multiple decorators"""
pass
Best Practices
- Always use
@functools.wraps when creating custom decorators
- Preserve function metadata for better debugging
- Maintain function's original characteristics
functools.wraps has minimal performance overhead and is recommended for most decorator implementations.
LabEx suggests incorporating functools.wraps as a standard practice in decorator design to ensure clean, maintainable code.