Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Is there are more readable way to check if a key buried in a dict exists without checking each level independently?

Lets say I need to get this value in a object buried (example taken from Wikidata):

x = s['mainsnak']['datavalue']['value']['numeric-id'] 

To make sure that this does not end with a runtime error it is necessary to either check every level like so:

if 'mainsnak' in s and 'datavalue' in s['mainsnak'] and 'value' in s['mainsnak']['datavalue'] and 'nurmeric-id' in s['mainsnak']['datavalue']['value']:     x = s['mainsnak']['datavalue']['value']['numeric-id'] 

The other way I can think of to solve this is wrap this into a try catch construct which I feel is also rather awkward for such a simple task.

I am looking for something like:

x = exists(s['mainsnak']['datavalue']['value']['numeric-id']) 

which returns True if all levels exists.

like image 207
loomi Avatar asked Apr 19 '17 09:04

loomi


People also ask

How do you check if a nested key exists in a dictionary Python?

The answer 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.

How do you check if a value exists in a nested dictionary?

Use get() and Key to Check if Value Exists in a Dictionary Dictionaries in Python have a built-in function key() , which returns the value of the given key.

How do you check if a key is inside a dictionary?

How do you check if a key exists or not in a dictionary? You can check if a key exists or not in a dictionary using if-in statement/in operator, get(), keys(), handling 'KeyError' exception, and in versions older than Python 3, using has_key(). 2.

How do you break nested dictionaries in Python?

In Python, we use “ del “ statement to delete elements from nested dictionary.


2 Answers

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) 
like image 79
Arount Avatar answered Sep 16 '22 20:09

Arount


You could use .get with defaults:

s.get('mainsnak', {}).get('datavalue', {}).get('value', {}).get('numeric-id') 

but this is almost certainly less clear than using try/except.

like image 25
Daniel Roseman Avatar answered Sep 20 '22 20:09

Daniel Roseman