Reputation: 14853
When I wrap a function with @
, how do I make the wrapper function look & feel exactly like the wrapped function? help(function)
in particular.
Some code:
>>> def wraps(f):
def call(*args, **kw):
print('in', f, args, kw) # example code. I need to transfer the arguments to another process and pickle them.
return f(*args, **kw)
return call
>>> def g():pass
>>> @wraps
def f(a, b = 1, g = g, *args, **kw):
pass
>>> help(f)
Help on function call in module __main__:
call(*args, **kw) # this line bothers me. It should look different, look below
>>> def f(a, b = 1, g = g, *args, **kw):
pass
>>> help(f)
Help on function f in module __main__:
f(a, b=1, g=<function g at 0x02EE14B0>, *args, **kw) # help(f) should look like this.
Motivation: It would also be nice to see the arguments when the help window pops up, when I type f(
* plopp * I see (a, b = 1, g = g, *args, **kw)
. (in this case in the IDLE Python Shell)
I had a look at the inspect
module which helps me with nice formatting. The problem is still there: how do I do this with arguments..
Default mutable argument passing like def f(d = {}):
does not need to work since I transfer the arguments to another process and the identity would be lost anyway.
Upvotes: 3
Views: 883
Reputation: 4959
I think the other answers are preferable, but if for some reason you don't want to use an external module, you could always alter your decorator like so:
def wraps(f):
def call(*args, **kw):
print('in', f, args, kw)
return f(*args, **kw)
call.__name__ = f.__name__
call.__doc__ = f.__doc__
return call
Upvotes: 1
Reputation: 879143
functools.wraps
can be used to copy the name and docstring of the function. Copying the original function signature is considerably harder to do from scratch.
If you use the third-party decorator module, however, then
import decorator
@decorator.decorator
def wraps(f):
def call(*args, **kw):
print('in', f, args, kw)
return f(*args, **kw)
return call
def g():pass
@wraps
def f(a, b = 1, g = g, *args, **kw):
pass
help(f)
yields
Help on function f in module __main__:
f(a, b=1, g=<function g>, *args, **kw)
Upvotes: 3
Reputation: 25954
Use functools.wraps
:
from functools import wraps
def wrapper(f):
@wraps(f)
def call(*args, **kw):
print('in', f, args, kw)
return f(*args, **kw)
return call
@wrapper
def f(a, b = 1, g = g, *args, **kw):
pass
help(f)
Help on function f in module __main__:
f(a, b=1, g=<function g at 0x7f5ad14a6048>, *args, **kw)
This preserves the __name__
and __doc__
attributes of your wrapped function.
Upvotes: 2