Suppose I have a function that I do not control that looks something like the following:
def some_func(foo, bar, bas, baz):
do_something()
return some_val
Now I want to call this function passing elements from a dict that contains keys that are identical to the arguments of this function. I could do something like:
some_func(foo=mydict['foo'],
bar=mydict['bar'],
bas=mydict['bas'],
baz=mydict['baz'])
Is there some elegant way I could take advantage of the fact that the keys match the parms to do this less verbosely? I know I could pass the whole dict, but let's say I either don't want to or can't change the function to accept a single dict rather than the individual arguments.
Thanks, Jerry
That's what **
argument unpacking is for:
some_func(**mydict)
See also Unpacking argument lists in the Python tutorial.
As Sven notes, you can pass a dict
to a function using **
unpacking. But if the dict
contains keys that aren't argument names to the target function, this works only if the function you're calling accepts keyword arguments using the **
notation. If it doesn't, you'll get an error.
If the function you're calling doesn't have a **kwargs
parameter, the easiest way to handle it is to add one. But if you can't do that, you have a couple approaches:
1) Write a wrapper function:
def wrapper(foo, bar, baz, quux, **kwargs):
return some_func(foo, bar, baz, quux)
wrapper(**mydict)
2) Write a function to extract just the dict keys you need:
def extract(dikt, keys):
return dict((k, dikt[k]) for k in keys.split())
some_func(**extract(mydict, "foo bar baz quux"))
3) Write a function that introspects the function you're calling and extracts the keys you need from the dictionary -- basically the same as #2 except you don't have to "repeat yourself" as much.
def call_with_dict(func, dikt):
func(**dict((k, dikt[k]) for k in
func.func_code.co_varnames[:func.func_code.co_argcount]))
call_with_dict(some_func, my_dict)
Note that this doesn't allow you to omit arguments that have default values in the function signature. You could do some additional introspection to permit that (the length of func.func_defaults
determines which of the arguments have default values).
This introspection is for Python 2.x, Python 3 and later will probably need some tweaking. For this reason, I prefer one of the first two methods.
PS -- Thanks to Sven for catching my missing **
in my second approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With