Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass keyword arguments as parameters to a function?

Say I have a function defined thus:

def inner_func(spam, eggs):
    # code

I then want to call a function like this:

outer_func(spam=45, eggs="blah")

Inside outer_func I want to be able to call inner_func with exactly the same parameters that were passed into outer_func.

This can be achieved by writing outer_func like this:

def outer_func(spam, eggs):
    inner_func(spam, eggs)

However, I'd like to be able to change the arguments inner_func takes, and change the parameters I pass to outer_func accordingly, but without having to change anything in outer_func each time.

Is there a (easy) way to do this? Python 3 please.

like image 868
Tom Burrows Avatar asked Mar 10 '17 17:03

Tom Burrows


People also ask

How do you pass keyword arguments?

The double asterisk form of **kwargs is used to pass a keyworded, variable-length argument dictionary to a function. Again, the two asterisks (**) are the important and along with the word kwargs, indicate that there is a dictionary of variable-length keyworded arguments.

How do you pass keyword arguments to a function in Python?

**kwargs allows us to pass a variable number of keyword arguments to a Python function. In the function, we use the double-asterisk ( ** ) before the parameter name to denote this type of argument.

Can a function define arguments and keyword arguments?

Functions can also be called using keyword arguments of the form kwarg=value . During a function call, values passed through arguments need not be in the order of parameters in the function definition.


2 Answers

Looks like you're looking for the * and ** notations:

def outer_func(*args, **kwargs):
    inner_func(*args, **kwargs)

Then you can do outer_func(1, 2, 3, a='x', b='y'), and outer_func will call inner_func(1, 2, 3, a='x', b='y').

If you only want to allow keyword arguments, drop the *args.


In a function definition, a parameter marked with * receives a tuple of all positional arguments that didn't correspond to other declared parameters, and an argument marked with ** receives a dict of all keyword arguments that didn't correspond to other declared parameters.

In a function call, prefixing a sequence (or other iterable) argument with * unpacks it into separate positional arguments, and prefixing a mapping argument with ** unpacks it into separate keyword arguments.

like image 167
user2357112 supports Monica Avatar answered Nov 02 '22 01:11

user2357112 supports Monica


Not entirely sure I'm getting your drift but you may find functools.wraps interesting:

@functools.wraps(inner_func)
def outer_func(*args, **kwds):
    return inner_func(*args, **kwds)

inspect.signature(outer_func)
# <Signature (spam, eggs)>

Explanation: The "star arguments" collect all the not explicitly specified postional (*args) and keyword (**kwds) arguments that were passed. They can also be used to pass these parameters on; or to manipulate them: args is a tuple and kwds is a dict.

Since for example parameter spam will end up either in args or kwds depending on how it was passed, manually parsing star args can be tedious. Here the inspect.Signature class and in particular its .bind and .bind_partial methods are useful.

functools.wraps is a convenience function/decorator that tweaks many special attributes of the decorated function to make it look like the wrapped function. In particular it copies the name, the signature, the doc string and whatever may be in the wrapped functions __dict__.

This makes wrapper functions much more user friendly.

like image 43
Paul Panzer Avatar answered Nov 02 '22 03:11

Paul Panzer