expanding dictionary to function arguments
Bengt Richter
bokr at oz.net
Wed Nov 2 12:42:00 EST 2005
On 1 Nov 2005 17:17:00 -0800, "Noah" <noah at noah.org> wrote:
>I have a dictionary that I would like to expand to satisfy a
>function's agument list. I can used the ** syntax to pass a dictionary,
>but
>this only works if each key in the dictionary matches an argument.
>I cannot pass a dictionary that has more keys than the function has
>arguments.
[...]
>I created the following function to do what I am describing.
>This isn't too bad, but I thought that perhaps there was some
>secret Python syntax that will do this for me.
>
>def apply_smart (func, args):
> """This is similar to func(**args), but this won't complain about
> extra keys in 'args'. This ignores keys in 'args' that are
> not required by 'func'. This passes None to arguments that are
> not defined in 'args'. That's fine for arguments with a default
>valeue, but
> that's a bug for required arguments. I should probably raise a
>TypeError.
> """
Ok, so why not do it? ;-)
> if hasattr(func,'im_func'): # Handle case when func is a class
>method.
> func = func.im_func
skipself = True
else: skipself = False
> argcount = func.func_code.co_argcount
Make arg list and call with it instead of
> required_args = dict([(k,args.get(k)) for k in
>func.func_code.co_varnames[:argcount]])
> return func(**required_args)
try:
required_args = [args[k] for k in func.func_code.co_varnames[skipself:argcount]]
except KeyError:
raise TypeError, '%s(...) missing arg %r'%(func.func_name, k)
return func(*required_args)
>
>So, I now I can do this:
> options = read_config ("options.conf")
> apply_smart (extract_audio, options)
> apply_smart (compress_audio, options)
> apply_smart (mux, options)
>
>Neat, but is that the best I can do?
>
I suppose you could replace your local bindings of extract_audio, compress_audio, and mux
with wrapper functions of the same name that could cache the func and arg names in closure
variables, e.g., using a decorator function (virtually untested)
def call_with_args_from_dict(func):
argnames = func.func_code.co_varnames[hasattr(func, 'im_func'):func.func_code.co_argcount]
ndefaults = len(func.func_defaults or ())
if ndefaults:
defnames = argnames[-ndefaults:]
argnames = argnames[:-ndefaults]
else:
defnames = []
def _f(**args):
try:
actualargs = [args[argname] for argname in argnames]
for argname in defnames:
if argname not in args: break
actualargs.append(args[argname])
except KeyError: raise TypeError, '%s(...) missing arg(s) %r'%(
func.func_name, [argname for argname in argnames if argname not in args])
return func(*actualargs)
_f.func_name = func.func_name
return _f
and then wrap like
extract_audio = call_with_args_from_dict(extract_audio)
or use as a decorator if you are defining the function to be wrapped, e.g.,
@call_with_args_from_dict
def mux(firstarg, second, etc):
...
Regards,
Bengt Richter
More information about the Python-list
mailing list