Reputation: 35
def decor(fun):
def living(*args, **kw):
return fun(*args, **kw)
return living
@decor
def test():
'''function doc'''
pass
print test.__doc__
why the result is None
? Something happened when I use decorator? Thanks to answer!
Upvotes: 2
Views: 703
Reputation: 122142
Because when you wrap a function in a decorator:
@decor
def test:
you get back the function created by the decorator, (living
, in this case) which doesn't have the same docstring, etc. It doesn't "lose" this data, living
never had it!
You can get around this with functools.wraps
:
from functools import wraps
def decor(fun):
@wraps(fun)
def living(*args, **kw):
...
return func
A quick demo to prove the point:
>>> def wrapper(f):
def func(*args):
"""The wrapper func's docstring."""
return f(*args)
return func
>>> @wrapper
def test(x):
"""The test func's docstring."""
return x ** 2
>>> test.__doc__
"The wrapper func's docstring."
versus
>>> from functools import wraps
>>> def wrapper(f):
@wraps(f)
def func(*args):
"""The wrapper func's docstring."""
return f(*args)
return func
>>> @wrapper
def test(x):
"""The test func's docstring."""
return x ** 2
>>> test.__doc__
"The test func's docstring."
Upvotes: 1
Reputation: 12077
That's because your decorator is basically replacing your function. You need to use functools.wraps()
to store the decorated functions internals like __name__
and __doc__
.
You can test this easily by adding a docstring to your decorator function living()
:
>>> def decor(fun):
... def living(*args, **kw):
... """This is the decorator for living()"""
... return fun(*args, **kw)
... return living
...
>>> @decor
... def test():
... """function doc"""
... pass
...
>>> test.__doc__
'This is the decorator for living()'
Example from the docs of functools.wraps()
which saves the wrapped functions name and docstring.
>>> from functools import wraps
>>> def my_decorator(f):
... @wraps(f)
... def wrapper(*args, **kwds):
... print 'Calling decorated function'
... return f(*args, **kwds)
... return wrapper
...
>>> @my_decorator
... def example():
... """Docstring"""
... print 'Called example function'
...
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'
Upvotes: 0