一尘不染

优雅的方法来检查字典中是否存在嵌套键?

python

是否有更可读的方法来检查是否存在嵌入字典的键而无需独立检查每个级别?

可以说我需要在埋藏的对象中获取此值(示例取自Wikidata):

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

为了确保不会以运行时错误结束,有必要检查每个级别,如下所示:

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']

我可以想到的另一种解决方法是将其包装到一个try catch结构中,对于这样一个简单的任务,我也觉得很尴尬。

我正在寻找类似的东西:

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

True如果所有级别都存在,则返回。


阅读 168

收藏
2021-01-20

共1个答案

一尘不染

简而言之,使用Python,您必须相信请求宽恕比允许许可容易

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

答案

这是我处理嵌套dict键的方法:

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

例:

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"))

输出:

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

它以给element定的顺序循环测试给定的每个键。

variable.get('key', {})我发现的所有方法相比,我都更喜欢此方法,因为它遵循EAFP

功能除外,例如:keys_exists(dict_element_to_test, 'key_level_0', 'key_level_1', 'key_level_n', ..)。至少需要两个参数,元素和一个键,但是您可以添加所需的键数。

如果您需要使用某种地图,则可以执行以下操作:

expected_keys = ['spam', 'egg', 'bacon']
keys_exists(data, *expected_keys)
2021-01-20