Decorators normally strip function metadata as they aren't the same. This can cause problems when using meta-programming to dynamically access function metadata. Metadata also includes function's docstrings and its name.
functools.wraps makes the decorated function look like the original function by copying several attributes to the wrapper function.
from functools import wraps
The two methods of wrapping a decorator are achieving the same thing in hiding that the original function has been decorated. There is no reason to prefer the function version to the class version unless you're already using one over the other.
def decorator(func): # Copies the docstring, name, annotations and module to the decorator @wraps(func) def wrapped_func(*args, **kwargs): return func(*args, **kwargs) return wrapped_func @decorator def test(): pass test.__name__
class Decorator(object): def __init__(self, func): # Copies name, module, annotations and docstring to the instance. self._wrapped = wraps(func)(self) def __call__(self, *args, **kwargs): return self._wrapped(*args, **kwargs) @Decorator def test(): """Docstring of test.""" pass test.__doc__
'Docstring of test.'