Python Check Multi-Level Dict Key Existence

python check multi-level dict key existence

UPDATE: I ended up writing my own open-source, pippable library that allows one to do this: https://pypi.python.org/pypi/dictsearch

python check existence of multiple multi level dict keys

This looks like the perfect situation for a recursive function.

The following function takes as arguments a dictionary (event), an ordered list of keys and a counter variable n incremented at each recursion.

The function looks for the n-th element of keys in the event dictionary; if it finds the key, the respective value is assigned to the event variable, the counter is incremented and the function is called recursively with the new parameters.

If the key is not found, or the n-th element is out of keys' range, or if event is not a dict type anymore, the program stops and prints out the event variable itself, which is indeed the value of the key used in the previous recursion.

Also if the very first key is not found in the dictionary, an error is shown.

def find_key(event, keys, n=0):
try:
event = event[keys[n]]
n += 1
find_key(event, keys, n=n)
except:
print(event if n != 0 else "The first key you provided was not found in the dictionary.")

As you can see, the code's logic is pretty simple and straightforward, so for instance:

event = {"key1":{"key2":{"key3":{"key4": "Hello World!"}}}}
keys = ["key1", "key2", "key3", "key4"]

find_key(event, keys)

would print out:

>>>Hello World!

Elegant way to check if a nested key exists in a dict?

To be brief, with Python you must trust it is easier to ask for forgiveness than permission

try:
x = s['mainsnak']['datavalue']['value']['numeric-id']
except KeyError:
pass

The answer

Here is how I deal with nested dict keys:

def keys_exists(element, *keys):
'''
Check if *keys (nested) exists in `element` (dict).
'''
if not isinstance(element, dict):
raise AttributeError('keys_exists() expects dict as first argument.')
if len(keys) == 0:
raise AttributeError('keys_exists() expects at least two arguments, one given.')

_element = element
for key in keys:
try:
_element = _element[key]
except KeyError:
return False
return True

Example:

data = {
"spam": {
"egg": {
"bacon": "Well..",
"sausages": "Spam egg sausages and spam",
"spam": "does not have much spam in it"
}
}
}

print 'spam (exists): {}'.format(keys_exists(data, "spam"))
print 'spam > bacon (do not exists): {}'.format(keys_exists(data, "spam", "bacon"))
print 'spam > egg (exists): {}'.format(keys_exists(data, "spam", "egg"))
print 'spam > egg > bacon (exists): {}'.format(keys_exists(data, "spam", "egg", "bacon"))

Output:

spam (exists): True
spam > bacon (do not exists): False
spam > egg (exists): True
spam > egg > bacon (exists): True

It loop in given element testing each key in given order.

I prefere this to all variable.get('key', {}) methods I found because it follows EAFP.

Function except to be called like: keys_exists(dict_element_to_test, 'key_level_0', 'key_level_1', 'key_level_n', ..). At least two arguments are required, the element and one key, but you can add how many keys you want.

If you need to use kind of map, you can do something like:

expected_keys = ['spam', 'egg', 'bacon']
keys_exists(data, *expected_keys)

Python : check if the nested dictionary exist

Here's the explicit short code with try/except:

try:
dict1['layer1']['layer2'][0]['layer3']
except KeyError:
present = False
else:
present = True

if present:
...

To get the element:

try:
obj = dict1['layer1']['layer2'][0]['layer3']
except KeyError:
obj = None # or whatever

Check key existence in nested dictionaries

If you are working with JSON, you can write a simple class to use with the dict as it is imported.

Given the following bit of JSON:

>>> js='{"a": {"b": {"c": {"d": "e"}}}}'

It would usually be decoded into a Python dict if it is comprised of object pairs:

>>> import json
>>> json.loads(js)
{u'a': {u'b': {u'c': {u'd': u'e'}}}}

As a normal Python dict, it is subject to KeyError with missing keys. You can use the __missing__ hook to override KeyErrors and achieve your original structure:

class Mdict(dict):
def __missing__(self, key):
return False

Now test that:

>>> md=Mdict({'a':Mdict({'b':Mdict({'c':Mdict({'d':'e'})})})})
>>> if md['a']['b']['d']:
... print md['a']['b']['d']
... elif md['a']['b']['c']:
... print 'elif', md['a']['b']['c']
...
elif {'d': 'e'}

Each level of the dict needs to be an Mdict vs a normal Python dict. If you are working with JSON, however, this is really easy to achieve. Just apply object_pairs_hook as you decode the JSON:

>>> js
'{"a": {"b": {"c": {"d": "e"}}}}'
>>> md=json.loads(js, object_pairs_hook=Mdict)

And that applies the class Mdict instead the default Python dict as the JSON is decoded.

>>> md
{u'a': {u'b': {u'c': {u'd': u'e'}}}}
>>> md['a']
{u'b': {u'c': {u'd': u'e'}}}
>>> md['a']['c']
False

The rest of the example here remains the same.

Check if at least one key of dict is contained in another dict

Use set intersections:

needed_keys = {key1, key2}

for d in data:
if needed_keys.intersection(d):
valid_data.append(d)

The intersection is only empty if no keys are shared between the needed_keys set and the dictionary.

Note that your any(...) function would work too, just not as efficiently as the set intersection option; perhaps you didn't realise that the any() function actually exists?

Reaching into a nested dictionary several levels deep (that might not exist)

You can use a recursive function:

def get_value(mydict, keys):
if not keys:
return mydict
if keys[0] not in mydict:
return 0
return get_value(mydict[keys[0]], keys[1:])

If keys can not only be missing, but be other, non-dict types, you can handle this like so:

def get_value(mydict, keys):
if not keys:
return mydict
key = keys[0]
try:
newdict = mydict[key]
except (TypeError, KeyError):
return 0
return get_value(newdict, keys[1:])


Related Topics



Leave a reply



Submit