简体   繁体   中英

Pythonic way to write wrapper functions

Let's say I have a function foo that gets a few parameters

def foo(width, height, depth=0):
    ...

I want to write a wrapper function that gets all of foo 's parameters and passes them on, eg

def goo(width, height, depth=0):
    ...
    foo(width, height, depth)
    ...

But this is ugly, since I have to repeat the variables and the default values.

What's the idiomatic way to do this in python?

A few options I thought about:

  1. passing to goo a dictionary called foo_params and calling foo(**foo_params) but then is error prone since I don't know if all the arguments are there

  2. writing another wrapper for foo that checks if the params with default values are None and if so doesn't pass them

  3. Putting the default values as constants so I won't repeat them

You can use *args and **kwargs syntax to pass an unknown amount of arguments and/or keyword arguments:

>>> def dec(func):
    def inner(*args, **kwargs):
        print('decorated function')
        func(*args, **kwargs)
    return inner

>>> @dec
def func(a, b):
    return a + b

>>> func(1, 2)
decorated function
>>> 

One downside to using *args and **kwargs is that you'll lose the orginal function signature of the decorated function. eg:

>>> help(func)
Help on function inner in module __main__:

inner(*args, **kwargs)

>>> 

The solution is to use functools.wraps() . It basically copies of the data from the decorated function to the wrapper function:

>>> from functools import wraps
>>> 
>>> def dec(func):
    @wraps(func)
    def inner(*args, **kwargs):
        print('decorated function')
        func(*args, **kwargs)
    return inner

>>> @dec
def func(a, b):
    return a + b

>>> func(1, 2)
decorated function
>>> 

A you can see below, if you now do help(func) the original signature for func will be displayed:

>>> help(func)
Help on function func in module __main__:

func(a, b)

>>>

I think you are looking for functools's partial function:

from functools import partial

def foo(a,b):
    return a + b

goo = partial(foo, b = 1)

goo(5)   # returns 6

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM