Python dict easiest and cleanest way to get value of key2 if key1 is not present

Viewed 211

I have a python dict like this,

d = {
"k1" : "v1",
"k2" : "v2"
}

I want to pick up value of k1 from dict, which I can do like this,

d.get("k1")

But the problem is, sometimes k1 will be absent in the dict. In that case, I want to pick k2 from the dict. I do it like this now

val = d.get("k1", None)
if not val:
    val = d.get("k2", None)

I can do like this as well,

if "k1" in d:
    val = d['k1']
else:
    val = d.get("k2", None)

These solutions look okay and works as expected, I was wondering if there exists a one-liner solution to this problem.

4 Answers

The None in d.get() specifies what to do if nothing is found.

Simply add another d.get() instead of None.

d.get('k1', d.get('k2', None))
#'v1'

A d.get inside a d.get:

Maybe try a double dict.get:

val = d.get("k1", d.get("k2", None))

And now:

print(val)

Would give k1's value if there is a k1 and k2's value if there isn't a key named k1, but if there also isn't a k2, it gives None.

My code does a d.get, but inside the parameters the second argument you did None, in this case we do another d.get, which is for k2, and in the second d.get it finally has the second argument as None, it only gives None if both of the keys are not in d.

Edit:

If there are more keys (i.e. k3, k4 ...), just add more d.gets:

val = d.get("k1", d.get("k2", d.get("k3", d.get("k4"))))

And just add a:

print(val)

To output it.

Using a generator with next:

You could also use a generator with next to get the first value, like this:

val = next((d[i] for i in ['k1', 'k2', 'k3', 'k4'...] if i in d), None)

And now:

print(val)

Would also give the right result.

Remember to add a None so that if there aren't any values from any of those keys it won't give a StopIteration.

If there's no built-in function which does what you want, then you can write your own; you only have to write it once, and then everywhere else that you actually use it, it's a one-liner.

def get_alt(d, *keys, default=None):
    return next((d[k] for k in keys if k in d), default)

Examples:

>>> my_dict = {'a': 1, 'b': 2, 'c': 3}
>>> get_alt(my_dict, 'a', 'b', 'c')
1
>>> get_alt(my_dict, 'd', 'b', 'c')
2
>>> get_alt(my_dict, 'd', 'e', 'c')
3
>>> get_alt(my_dict, 'd', 'e', 'f') is None
True
>>> get_alt(my_dict, 'd', 'e', 'f', default=4)
4
val = d.get("k1") or d.get("k2")

This is equivalent to your "I do it like this now" solution. None is the get's default, no need to specify it. And unlike the nested gets posted by others, this doesn't execute both gets if the first one succeeds.

Related