Why does Decorator Need @wrapsΒΆ

@wraps preserve attributes of the original function, otherwise attributes of the decorated function will be replaced by wrapper function. For example

Without @wraps

>>> def decorator(func):
...     def wrapper(*args, **kwargs):
...         print('wrap function')
...         return func(*args, **kwargs)
...     return wrapper
...
>>> @decorator
... def example(*a, **kw):
...     pass
...
>>> example.__name__  # attr of function lose
'wrapper'

With @wraps

>>> from functools import wraps
>>> def decorator(func):
...     @wraps(func)
...     def wrapper(*args, **kwargs):
...         print('wrap function')
...         return func(*args, **kwargs)
...     return wrapper
...
>>> @decorator
... def example(*a, **kw):
...     pass
...
>>> example.__name__  # attr of function preserve
'example'