Search code examples
pythonpython-3.xdecoratorpython-decoratorsdocstring

Where to put the doc string for a decorator


I'm trying to document a decorator, but am not sure where the doc string should go. Technically, it's the inner wrapper that contains the parameters I want to document, but a user is going to be applying the outer function name as the decorator.

For example,

def change_case(func):
    """Does the doc string go here
    """
    def _wrapper(s, case=None):
        """Or, does the doc string go here?
        """
        if case == 'Upper':
            s = s.upper()
        elif case == 'Lower':
            s = s.lower()
        return func(s)

    return _wrapper

@change_case
def echo(s):
    return s

echo('Test', case='Upper')

In the above, does the doc string go after change_case() or _wrapper(). I'm leaning towards the former.


Solution

  • Put the documentation for the actually decorator in the top-level decorator function. When a user is attempting to use your decorator, this is where they would expect to find the documentation for it. For example, take the functools.singledispatch decorator from the standard library:

    >>> from functools import singledispatch
    >>>
    >>> print(singledispatch.__doc__) # the decorator has it's documentation in the actually decorator function
    Single-dispatch generic function decorator.
    
        Transforms a function into a generic function, which can have different
        behaviours depending upon the type of its first argument. The decorated
        function acts as the default implementation, and additional
        implementations can be registered using the register() attribute of the
        generic function.
    
    
    >>>
    

    However, you should also use functools.wraps to transfer any documentation contained in the decorated function to the wrapper function:

    >>> from functools import wraps
    >>>
    >>> def dec(func):
    ...     @wraps(func)
    ...     def wrap(*args, **kwargs):
    ...         return func(*args, **kwargs)
    ...     return wrap
    ...
    >>> @dec
    ... def func():
    ...     """Docstring here"""
    ...
    >>> print(func.__doc__)
    Docstring here
    >>>