python检查多级dict密钥存在

时间:2014-11-17 18:08:35

标签: python dictionary

许多SO帖子向您展示如何有效地检查字典中是否存在密钥,例如Check if a given key already exists in a dictionary

如何为多级密钥执行此操作?例如,如果d["a"]["b"]是一个字典,我如何检查d["a"]["b"]["c"]["d"]是否存在而不做像这样可怕的事情:

if "a" in d and isInstance(d["a"], dict) and "b" in d["a"] and isInstance(d["a"]["b"], dict) and ...

是否有类似

的语法
if "a"/"b"/"c"/"d" in d

我实际使用的是:我们有jsons,使用simplejson解析为dicts,我需要从中提取值。其中一些值嵌套了三层和四层深度;但有时价值根本不存在。所以我想要这样的东西:

val = None if not d["a"]["b"]["c"]["d"] else  d["a"]["b"]["c"]["d"] #here d["a"]["b"] may not even exist

编辑:如果某个子项存在但不是字典,则不要崩溃,例如d["a"]["b"] = 5

4 个答案:

答案 0 :(得分:10)

可悲的是,没有任何内置语法或公共库来查询这样的词典。

但是,我相信你能做的最简单的事情(我觉得它足够有效)是:

d.get("a", {}).get("b", {}).get("c")

编辑:它不常见,但有:https://github.com/akesterson/dpath-python

编辑2 :示例:

>>> d = {"a": {"b": {}}}
>>> d.get("a", {}).get("b", {}).get("c")
>>> d = {"a": {}}
>>> d.get("a", {}).get("b", {}).get("c")
>>> d = {"a": {"b": {"c": 4}}}
>>> d.get("a", {}).get("b", {}).get("c")
4

答案 1 :(得分:3)

这不是一个好主意,我不建议在生产中使用它。但是,如果您只是为了学习目的而这样做,那么下面的内容可能适合您。

def rget(dct, keys, default=None):
    """
    >>> rget({'a': 1}, ['a'])
    1
    >>> rget({'a': {'b': 2}}, ['a', 'b'])
    2
    """
    key = keys.pop(0)
    try:
        elem = dct[key]
    except KeyError:
        return default
    except TypeError:
        # you gotta handle non dict types here
        # beware of sequences when your keys are integers
    if not keys:
        return elem
    return rget(elem, keys, default)

答案 2 :(得分:2)

更新:我最终编写了自己的开源,可发布的库,允许其执行此操作:https://pypi.python.org/pypi/dictsearch

答案 3 :(得分:0)

一个非递归版本,与@Meitham的解决方案非常相似,它不会更改查找键。如果源词典中存在 exact 结构,则返回True / False

def subkey_in_dict(dct, subkey):
    """ Returns True if the given subkey is present within the structure of the source dictionary, False otherwise.
    The format of the subkey is parent_key:sub_key1:sub_sub_key2 (etc.) - description of the dict structure, where the
    character ":" is the delemiter.

    :param dct: the dictionary to be searched in.
    :param subkey: the target keys structure, which should be present.
    :returns Boolean: is the keys structure present in dct.
    :raises AttributeError: if subkey is not a string.
    """
    keys = subkey.split(':')
    work_dict = dct
    while keys:
        target = keys.pop(0)
        if isinstance(work_dict, dict):
            if target in work_dict:
                if not keys:    # this is the last element in the input, and it is in the dict
                    return True
                else:   # not the last element of subkey, change the temp var
                    work_dict = work_dict[target]
            else:
                return False
        else:
            return False

检查的结构的格式为parent_key:sub_key1:sub_sub_key2,其中:字符是定界符。显然-区分大小写,如果字典中有列表,它将停止(返回False)。

样品用量:

dct = {'a': {'b': {'c': {'d': 123}}}}

print(subkey_in_dict(dct, 'a:b:c:d'))    # prints True
print(subkey_in_dict(dct, 'a:b:c:d:e'))  # False
print(subkey_in_dict(dct, 'a:b:d'))      # False
print(subkey_in_dict(dct, 'a:b:c'))      # True