Python
functools.wraps
Preserve decorator metadata with functools.wraps.
The wrapper loses identity
When a decorator wraps a target, metadata like __name__ and __doc__ moves to the wrapper. So hello.__name__ is no longer "hello" but "wrapper". This breaks debugging and help output.
The fix: write @functools.wraps(target) at the top of the wrapper. It copies the target's name, docstring and other metadata to the wrapper. From the outside the wrapper looks like the target.
What does wraps copy?
@functools.wraps(fn) copies not just the name but also attributes like __doc__, __module__, __qualname__ and __dict__. So help(hello) shows the real hello docstring, not the wrapper's.
Signature information also looks more accurate. This matters when writing libraries; users must know which function they call. Using wraps when writing decorators is a good habit.
Exercise A decorator that uses wraps
Start with import functools. Define a decorator named call; signature def call(fn):. Inside, write @functools.wraps(fn) on the line above def wrapper(*args, **kwargs):. The wrapper body should be return fn(*args, **kwargs). End with return wrapper. Decorate def hello(): with @call; body returns "Hi!". Finally call print(hello.__name__).
Show example solution
# Write the call decorator and the hello function
import functools
def call(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
return fn(*args, **kwargs)
return wrapper
@call
def hello():
return "Hi!"
print(hello.__name__)
Test yourself
-
What does @functools.wraps prevent from being lost?
- The parameters
- The function's return value
- The function name and docstring
- Error raising
Show answer
The function name and docstring — @functools.wraps prevents the target's name and docstring from moving to the wrapper.
-
Complete the wraps line
def call(fn):
@____(fn)
def wrapper(*args, **kwargs):
return fn(*args, **kwargs)
return wrapper
Show answer
def call(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
return fn(*args, **kwargs)
return wrapper
-
Match wraps and metadata
- __name__
- Function name
- __doc__
- Docstring
- __module__
- Defining module
- @functools.wraps
- Copies metadata
Next lesson: Summary - Property and decorator