Python decorator handling docstrings

Question:

I have a problem using docstrings with decorators. Given the following example:

def decorator(f):
    def _decorator():
        print 'decorator active'
        f()
    return _decorator

@decorator
def foo():
    '''the magic foo function'''
    print 'this is function foo'

help(foo)

Now the help doesn’t show me the docstring of foo as expected, it shows:

Help on function _decorator in module __main__:

_decorator()

Without the decorator, the help is correct:

Help on function foo in module __main__:

foo()
    the magic foo function

I know, that the function foo is wrapped by the decorator, and so the function object is not the function foo any more. But what is a nice solution to get the docstring (and the help) as expected?

Asked By: Günther Jena

||

Answers:

I found a solution, but don’t know if it’s really nice:

def decorator(f):
    def _decorator():
        print 'decorator active'
        f()
    _decorator.__name__=f.__name__
    _decorator.__doc__=f.__doc__
    return _decorator

The part with _decorator.__name__=f.__name__ seems a little bit hideous… What do you think?

Answered By: Günther Jena

Use functools.wraps() to update the attributes of the decorator:

from functools import wraps

def decorator(f):
    @wraps(f)
    def _decorator():
        print 'decorator active'
        f()
    return _decorator

@decorator
def foo():
    '''the magic foo function'''
    print 'this is function foo'

help(foo)

Also see the Standard Library documentation for functools.

Answered By: Pär Wieslander

Take a look at functools.wraps: http://docs.python.org/library/functools.html

Answered By: Mark Byers

The solution is pretty easy. The doc string should be mentioned in the top most decorator that is being called on top of the main function. Find the example below:

import math

def wrap2(func):
    def squarer(x):
        return [math.sqrt(i) for i in func(x)]
    return squarer
    

def wrap1(func):
    def summer(x):
        return [i*2 for i in func(x)]
    return summer

def wrap3(func):
    def rounder(x):
        return [round(i,1) for i in func(x)]
    return rounder

def wrap4(func):
    def stringer(x):
        '''
    Enter the input of a 2-dim array to get the output
    '''
        return [str(i)+' rounds ' for i in func(x)]
    return stringer

@wrap4
@wrap3
@wrap2
@wrap1
def rooter(i):
    return [sum(p) for p in i]

help(rooter)

# output
Help on function stringer in module __main__:

stringer(x)
    Enter the input of a 2-dim array to get the output

—or—-

Signature: rooter(x)
Docstring: Enter the input of a 2-dim array to get the output
File:      d:<ipython-input-392-487fc73b05cf>
Type:      function

So, the Doc String must be mentioned in the wrap4 decorator function for it to be visible in the main function.

Answered By: nvesram
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.