Issue
With the code below entered in ipython, entering subsequent func_with_wrap?
shows <no docstring>
while func_no_wrap?
shows the docstring as expected. How can I get func_with_wrap?
to properly show the docstring of func_with_wrap
?
def wrap(f):
"""
wrap docstring
"""
def wrapped():
return
return wrapped
@wrap
def func_with_wrap():
"""
func_with_wrap docstring
"""
return
def func_no_wrap():
"""
func_no_wrap docstring
"""
return
Here are the outputs:
In [12]: func_with_wrap?
Signature: func_with_wrap()
Docstring: <no docstring>
File: c:\confidential>
Type: function
In [13]: func_no_wrap?
Signature: func_no_wrap()
Docstring: func_no_wrap docstring
File: c:\confidential>
Type: function
EDIT:
When tryin the following:
def wrap(f):
"""
wrap docstring
"""
def wrapped():
wrapped.__doc__ = f.__doc__
return
return wrapped
ipython
still does not show func_with_wrap
's docstring.
BUT,
def wrap(f):
"""
wrap docstring
"""
def wrapped():
return
wrapped.__doc__ = f.__doc__
return wrapped
does work.
Solution
Because the function def wrapped():
(declared inside wrap
) has no docstring, no docstring is present for func_with_wrap
. Decorators work on functions by replacing them with the return value of the decorator passed the decorated function. It's mostly equivalent to the following named lambda behavior:
func_with_wrap = lambda: <code that was in 'def func_with_wrap' block>
func_with_wrap = wrap(func_with_wrap)
While you could add a docstring to the inner def wrapped
call in your example, that would be a bit unusual. Since most decorators are (as your symbol names suggest) wrappers that augment the decorated function rather than completely replacing it with something else, it's considered a best practice to propagate attributes (like the docstring, function name, and type annotations) from the function being wrapped--func_with_wrap
in your example--to the return value of the decorator--wrapped
in your example.
Most people do this using functools.wraps
, like so:
from functools import wraps
def wrap(f):
"""
wrap docstring
"""
@wraps(f)
def wrapped():
...
return wrapped
You can also do this by hand, by manually assigning __doc__
from the decorated function to the return value of the decorator, like this:
def wrap(f):
"""
wrap docstring
"""
def wrapped():
...
wrapped.__doc__ = f.__doc__
return wrapped
Answered By - Zac B
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.