wallacer
wallacer

Reputation: 13213

Let default value for parameter take precedence if test fails

This is just a curiosity question for a "good" pythonic way to do this.

I have a function with an optional parameter ie.

def foo( a, b, c='en' ):
    print c

There is a dict with a bunch of info in it, and if a particular key is in the dict, I would like to pass it into foo to override c's default, but if the key is not in the dict, I just want to use the default for c.

Obviously this will work...

if "SomeKey" in mydict:
    foo( val1, val2, mydict[ "SomeKey" ]
else:
    foo( val1, val2 )

And another option would be to do something like

params = [ val1, val2 ]
if "SomeKey" in mydict:
    params.append( mydict[ "SomeKey" ] )
foo( *params )

but there must be a slick, more pythonic way to do this? ie.

foo( val1, val2, mydict[ "SomeKey" ] if "SomeKey" in mydict else < use default > )

Thanks in advance!

Upvotes: 1

Views: 206

Answers (3)

mgilson
mgilson

Reputation: 310097

Can you mess with foo?

def foo(a,b,c='en',**kwargs):
    ...

Then to call it with your dictionary:

foo('bar','baz',**mydict)

an ugly way to do it (that doesn't mess with foo) would be:

foo( val1,val2,mydict[ "SomeKey" ]) if "SomeKey" in mydict else foo(val1,val2)

Although really, my preferred method -- assuming that foo cannot raise a KeyError would be: (especially if 'SomeKey' will be in the dict more often than not):

try:
    foo(val1,val2,c=mydict['SomeKey'])
except KeyError:
    foo(val1,val2)

This avoids repeated key lookups, and makes it explicit that you're calling a function with a default argument.


Or with inspect plus dict.get as mentioned by phihag:

foo(val1,val2,mydict.get('SomeKey',inspect.getargspec(foo).defaults[0]))

Note that if you use this one, and foo will be inspected repeatedly, you might want to save the result somewhere you can access it.

Upvotes: 2

Amber
Amber

Reputation: 527213

Don't use a "true" default value for this - instead, use a placeholder value:

def foo( a, b, c=None ):
    if c is None:
        c = 'en'
    print c

and then just call with...

foo( val1, val2, mydict.get("SomeKey") )

(.get() returns None if the key isn't in the dict, by default)


If you can't modify foo(), then you can do the more complex varargs path:

maybe_c = {'c': mydict["SomeKey"]} if "SomeKey" in mydict else {}
foo( val1, val2, **maybe_c )

Upvotes: 4

phihag
phihag

Reputation: 288190

If you know the default, you can use dict.get:

foo(val1, val2, mydict.get('SomeKey', 'en'))

Upvotes: 4

Related Questions