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.
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.
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 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.
In Python, we use “ del “ statement to delete elements from nested dictionary.
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
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)
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.
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