7

Let's say I have a custom decorator, and I want it to properly handle docstring of decorated function. Problem is: my decorator adds an argument.

from functools import wraps

def custom_decorator(f):
    @wraps(f)
    def wrapper(arg, need_to_do_more):
        '''
        :param need_to_do_more: if True: do more
        '''
        args = do_something(arg)

        if need_to_do_more:
            args = do_more(args)

        return f(args)

    return wrapper

You can see the argument is not actually passed to decorated function, but used by the wrapper - which may or may not be relevant here.

How can I properly handle documenting the additional argument? Is it a good practice for a wrapper to take an additional argument, or should I avoid it?

Or should I rather use a different solution, like:

  • making wrapper a simple higher order function, with the function it calls passed as the third argument
  • refactoring the wrapper into two separate functions?
1
  • Without a knowledge of Python, I assume, as it stands, no developer would see the :param comment in any IDE because the association only occurs at runtime. As such I'd suggest a "remarks"-like comment to custom_decorator that mentions there is an extra parameter.
    – Mark Hurd
    Dec 23, 2015 at 3:23

1 Answer 1

2

Changing method signature using decorator is something that in most cases violates Principle Of Least Astonishment:

The Principle of Least Astonishment states that the result of performing some operation should be obvious, consistent, and predictable, based upon the name of the operation and other clues.

The exceptions I could come up are:

  • decorator in its name clearly states that method signature is changed. Example of such decorator is @property.
  • decorated method is not intended to be invoked directly by client code
  • decorator is used for some kind of adaptation (like Adapter pattern)

Nevertheless, usually decorators are usually implemented for decorating functions (like in Decorator pattern, although authors of the decorator feature opposed this similarities), which implies that method signature (including list of parameters) is not changed.

As an alternative to implicitly adding new parameter I propose to make this explicit - any decorated function must declare such parameter on the list of parameters. You can check function parameter names using method described in this SO answer and throw exception if decorated function does not have such parameter.

Implicit parameter or requiring parameter should be described in decorator docstring (custom_decorator in your example). If you use @wraps decorator on returned function (wrapper in your example), __doc__ attribute is copied from function f and overwrites whatever docstring you specify for wrapper.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.