473,385 Members | 1,958 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

expanding dictionary to function arguments

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.

# Example 1 - This works:
# Prints "hello world!"
def foo (arg1='greetings', arg2='planet', arg3='.'):
print arg1 + ' ' + arg2 + arg3
args = {'arg1':'hello', 'arg2':'world', 'arg3':'!'}
foo (**args)

# Example 2 - This does not work:
# raises TypeError: foo() got an unexpected keyword argument 'arg4')
def foo (arg1='greetings', arg2='planet', arg3='.'):
print arg1 + ' ' + arg2 + arg3
args = {'arg1':'hello', 'arg2':'world', 'arg3':'!', 'arg4':'ignore'}
foo (**args)

As a practical application, I have a project where I have a config file

that defines a large number of keys and values. I read the config
file into a dictionary called "options". I also have an API module with
many
functions that I want to call with arguments taken directly from the
"options" dictionary. The key names in the "options" dictionary match
the argument names of the functions in my API.

# The ugly, brutish way:
options = read_config ("options.conf")
extract_audio (options['source_video_filename'])
compress_audio (options['audio_raw_filename'],
options['audio_compressed_filename'], options['audio_sample_rate'],
options['audio_bitrate'])
mux (options['source_video_filename'],
options['audio_compressed_filename'], options['output_video_filename'])

I know that the keys in my "options" dictionary match the arguments
of the functions in the API library, so I would like to do this:
options = read_config ("options.conf")
extract_audio (**options)
compress_audio (**options)
mux (**options)

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.
"""
if hasattr(func,'im_func'): # Handle case when func is a class
method.
func = func.im_func
argcount = func.func_code.co_argcount
required_args = dict([(k,args.get(k)) for k in
func.func_code.co_varnames[:argcount]])
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?

Yours,
Noah

Nov 2 '05 #1
4 3339
Noah a écrit :
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.


If you have control over the API functions declarations, makes them so:

def my_api_func(arg1='', arg2='whatever', **kwargs):
code_here

Nov 2 '05 #2

Bruno Desthuilliers a écrit :
Noah a écrit :
If you have control over the API functions declarations, makes them so:
def my_api_func(arg1='', arg2='whatever', **kwargs):
code_here


Unfortunately I cannot change the API functions.
I should have mentioned that.

Yours,
Noah

Nov 2 '05 #3
Noah wrote:
Bruno Desthuilliers a écrit :
Noah a écrit :
If you have control over the API functions declarations, makes them so:
def my_api_func(arg1='', arg2='whatever', **kwargs):
code_here

Unfortunately I cannot change the API functions.
I should have mentioned that.


Yeps... That what I thought, but you didn't mention it, and it was not
that clear (or it's me being stupid...).

I'm no great expert, but apart from writing a generic decorator for the
API objects and decorating them all with your smart_apply function -
which won't by you much in this case imho -, I don't see a much better
solution...

Some guru around ???

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Nov 2 '05 #4
On 1 Nov 2005 17:17:00 -0800, "Noah" <no**@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
Nov 2 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Jack Carter | last post by:
I have been delegated to produce a tool that has python embedded in it. The desire is to have a command line interface that inherits all the python scripting functionality so people can use the...
15
by: Stefan Behnel | last post by:
Hi! I'm trying to do this in Py2.4b1: ------------------------------- import logging values = {'test':'bla'} logging.log(logging.FATAL, 'Test is %(test)s', values)...
125
by: Raymond Hettinger | last post by:
I would like to get everyone's thoughts on two new dictionary methods: def count(self, value, qty=1): try: self += qty except KeyError: self = qty def appendlist(self, key, *values): try:
16
by: David Bear | last post by:
I know there must be a better way to phrase this so google understands, but I don't know how.. So I'll ask people. Assume I have a list object called 'alist'. Is there an easy way to create a...
8
by: s99999999s2003 | last post by:
hi i have a dictionary defined as execfunc = { 'key1' : func1 } to call func1, i simply have to write execfunc . but if i have several arguments to func1 , like execfunc = { 'key1' :...
2
by: Noah | last post by:
Is there a simple way to get a dictionary of argument names and their default values for a method or function? I came up with one solution, but I feel like Python must have a simpler way. ...
4
by: 63q2o4i02 | last post by:
Hi, I'm writing a hand-written recursive decent parser for SPICE syntax parsing. In one case I have one function that handles a bunch of similar cases (you pass the name and the number of...
36
by: James Harris | last post by:
Initial issue: read in an arbitrary-length piece of text. Perceived issue: handle variable-length data The code below is a suggestion for implementing a variable length buffer that could be used...
0
by: James Mills | last post by:
On Fri, Oct 31, 2008 at 8:49 AM, mark floyd <emfloyd2@gmail.comwrote: Mark, this is correct behavior. You have 3 positional arguments in the function definition. You _must_ aupply _all_ 3 of...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.