Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python decorator with arguments of decorated function

Tags:

python

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.

like image 870
User Avatar asked Jun 09 '26 10:06

User


2 Answers

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)
like image 82
unutbu Avatar answered Jun 12 '26 00:06

unutbu


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.

like image 40
roippi Avatar answered Jun 12 '26 00:06

roippi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!