Python decorator handling docstrings
Solution 1
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
.
Solution 2
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?
Solution 3
Take a look at functools.wraps
: http://docs.python.org/library/functools.html
![Günther Jena](https://i.stack.imgur.com/49k8V.jpg?s=256&g=1)
Günther Jena
I started programming with a Commodore Plus/4 (a successor of the famous C64). Hacking in BASIC became boring so I started to program in assembler. Learning C in school and C++, C# and Java later I ended up with Python, C and C++ as my favorite languages. I'm part time teacher at a polytechnical school in Austria teaching programming and digital electronics. In my main job I'm working on embedded systems for lasers.
Updated on June 13, 2022Comments
-
Günther Jena about 2 years
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 functionfoo
any more. But what is a nice solution to get the docstring (and the help) as expected? -
Scott Griffiths over 14 yearsThis doesn't work if
foo
takes any arguments - they get replaced by whatever the_decorator
uses. This is a problem especially when you want your decorator to take*args, **kwds
. I've never been able to find a way to get the docstring correct usingfunctools.wraps
. -
Pär Wieslander over 14 years@Scott Griffiths: The docstring will still be correct even if
foo
takes arguments. However,help(foo)
will display the parameter list of the_decorator
, since it actually replaces thefoo
function. There's no good way around this if you're writing decorators that take arbitrary arguments using*args, **kwargs
, but for me the important point is that the docstring is kept intact. Parameter details could always be specified in the docstring for clarity. -
Scott Griffiths over 14 yearsThanks for the extra information. I've recently been failing to get the help description correct for decorated functions - it seems a pretty poor state of affairs, but I understand the difficulty as the decorated function could have a completely different signature. Still, there must be a way... :)
-
thomas over 14 yearsIn fact this is (almost ?) exactly what functools.wraps do :)
-
Nadia Alramli over 14 yearsThere is a way to do it. The decorator module pypi.python.org/pypi/decorator does it by using a trick. The trick is to rebuild the decorator signature and run exec on it. You can find the trick in line 118 in decorator.py. I think however that this approach is extreme.
-
jcdyer over 14 yearsIt doesn't look hideous to me. It says exactly what you want it to say. "I want the name of this function to be 'myfunction' instead of '_decorator'."
-
John Carrell over 6 yearsIt seems that functools.wraps does enable
help()
to work properly now. I'm struggling to find when this changed but I'm still using Python 2.7. Happy day! -
MikeyE over 6 yearsHow would I use this method with the docorator
@classmethod
? -
Azat Ibrakov almost 6 yearsyou should not re-invent the wheel, especially when there is a working function from standard library which does this, well-tested, maintained and documented
-
oxer over 5 yearsWhat about putting a line like
_decorator.__doc__ += '\n(decorated by <decorator description>)'
right beforereturn _decorator
? Seems like that would make the docstring more informative but I haven't seen that so wondering if there is a reason not to do that. -
Markus about 5 yearsI cannot go along with @Azat Ibrakov; I'd always prefer a clear to read solution which is not dependent on any (also eventually changing) libraries. Therefore, I realy like this simple and straight forward approach (+1).
-
patzm about 3 yearsalso, this solution doesn't copy the docstrings of the arguments of
f
(if it had any) and return type.functools.wraps
does this though.