I am working with API calls and thus Python dictionaries.
However, for the same request, I don't always key the same keys, and I'd like to know when I can call a key without an Exception...
Let's say I have
test = {'a':{'b':{'c':{'d':'e'}}}}
Sometimes key d will exist, sometimes it won't. Sometimes c won't even exist.
I'd like to, somehow, check if test['a']['b']['c']['d']
exists, in one line.
What I've tried so far:
Using test.get('a', {}).get('b', {}).get('c', {}).get('d', {})
. Works fine but it's a mess, sometimes I have 5-6 nested dictionaries with really long names...
Using try/except block which is nice, but usually if test['a']['b']['c']['d']
does not exist, I will try calling test['a']['b']['e']['f']
to check if that one exists, thus I would need to add a try/catch for every of my if statements, as if I am not wrong, if an exception is catch, try block is not executed anymore.
I was maybe trying to look to a somekind of reflexive way to do it, calling a function with the name of my "object" as a string, that would check if every key exists, and if it does, return the object itself.
Any thoughts?
The usage behind it would be, omitting useless case, and assuming sometimes the info is in test['a']['b']['c']['d'], sometimes in test['a']['b']['f'] :
if test['a']['b']['c']['d'] **exists**:
do sthg with the value of test['a']['b']['c']['d']
elif test['a']['b']['f'] **exists**:
do sthg else with the value of test['a']['b']['f']
else:
do sthg different
If I put a try/except there, won't the first exception stop the execution and don't let me execute the elif?
Moreover, I really like the way of calling test['a']['b']['c']['d']
better than giving a list of keys. In fact, I want it to be as transparent as possible for me and for the people who will read/use my code.
Use get() and Key to Check if Value Exists in a Dictionary You can use this function as a condition to determine whether or not a value exists within a dictionary.
You can check if a key exists in a dictionary using the keys() method and IN operator. The keys() method will return a list of keys available in the dictionary and IF , IN statement will check if the passed key is available in the list. If the key exists, it returns True else, it returns False .
keys() function to make your code more explicit. To get a list of the dictionary's values, you can call the dict. values() function.
In Python, we use “ del “ statement to delete elements from nested dictionary.
You could write a recursive function to check:
def f(d, keys):
if not keys:
return True
return keys[0] in d and f(d[keys[0]], keys[1:])
If the function returns True, the keys exist:
In [10]: f(test,"abcd")
Out[10]: True
In [11]: f(test,"abce")
Out[11]: False
If you want to test multiple key combinations:
for keys in ("abce","abcr","abcd"):
if f(test,keys):
print(keys)
break
abcd
To return the value it is pretty simple:
def f(d, keys):
if len(keys) == 1:
return d[keys[0]] if keys[0] in d else False
return keys[0] in d and f(d[keys[0]], keys[1:])
print(f(test,"abcd"))
e
You can test again for multiple key combinations:
def test_keys(keys):
for keys in keys:
val = f(test,keys)
if val:
return val
return False
print(test_keys(("abce","abcr","abc")))
You can also write the function iteratively:
def f(d, keys):
obj = object
for k in keys:
d = d.get(k, obj)
if d is obj:
return False
return d
print(f(test,"abcd"))
e
If you want to run a condition based on the return values:
def f(d, keys):
obj = object
for k in keys:
d = d.get(k, obj)
if d is obj:
return False
return d
from operator import mul
my_actions = {"c": mul(2, 2), "d": lambda: mul(3, 3), "e": lambda: mul(3, 3)}
for st in ("abce", "abcd", "abcf"):
val = f(test, st)
if val:
print(my_actions[val]())
9
Just test the key combo in the same order you would with your if/elif's etc..
It's not exactly what you want because it doesn't check existence, but here's a one-liner similar to the dict.get
method:
In [1]: test = {'a':{'b':{'c':{'d':'e'}}}}
In [2]: keys = 'abcd' # or ['a', 'b', 'c', 'd']
In [3]: reduce(lambda d, k: d.get(k) if d else None, keys, test)
Out[3]: 'e'
In [4]: keys = 'abcf'
In [5]: reduce(lambda d, k: d.get(k) if d else None, keys, test)
Unfortunately it's not very efficient because it doesn't stop as soon as one of the keys is missing.
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