从字典构造一个嵌套的defaultdict?

时间:2018-12-28 16:17:31

标签: python dictionary

是否可以将here中讨论的方法扩展到嵌套的defaultdict?

编辑:

根据注释,默认值从原始的None更新为lambda: None。但是,以下内容仍然无法正常工作:

from collections import defaultdict
dd = defaultdict(lambda: None, {"a":1,"b":{"c":3}})

dd["b"]["e"]引发KeyError而不返回None。

如何将所有嵌套的dict转换为defaultdict?

3 个答案:

答案 0 :(得分:2)

您可以这样做:

from collections import defaultdict


def to_none(d, factory):
    result = defaultdict(factory)
    for key, value in d.items():
        if isinstance(value, dict):
            result[key] = to_none(value, factory)
        else:
            result[key] = value
    return result


d = {"a": 1, "b": {"c": 3}}

dd = to_none(d, lambda: None)

print(dd['a'])
print(dd['xxx'])
print(dd['b']['c'])
print(dd['b']['e'])

输出

1
None
3
None

答案 1 :(得分:1)

collections.defaultdict不是用于此目的的理想工具。要将None指定为嵌套字典的默认值,只需找到iterate your dictionary recursively并使用dict.get即可在找不到任何级别的键时返回None

from functools import reduce

def get_from_dict(dataDict, mapList):
    """Iterate nested dictionary"""
    return reduce(dict.get, mapList, dataDict)

d = {"a": 1, "b": {"c": 3}}

get_from_dict(d, ['b', 'e'])  # None
get_from_dict(d, ['b', 'c'])  # 3

答案 2 :(得分:0)

def _sub_getitem(self, k):
    try:
        # sub.__class__.__bases__[0]
        real_val = self.__class__.mro()[-2].__getitem__(self, k)
        val = '' if real_val is None else real_val
    except Exception:
        val = ''
        real_val = None
    # isinstance(Avoid,dict)也是true,会一直递归死
    if type(val) in (dict, list, str, tuple):
        val = type('Avoid', (type(val),), {'__getitem__': _sub_getitem, 'pop': _sub_pop})(val)
        # 重新赋值当前字典键为返回值,当对其赋值时可回溯
        if all([real_val is not None, isinstance(self, (dict, list)), type(k) is not slice]):
            self[k] = val
    return val


def _sub_pop(self, k=-1):
    try:
        val = self.__class__.mro()[-2].pop(self, k)
        val = '' if val is None else val
    except Exception:
        val = ''
    if type(val) in (dict, list, str, tuple):
        val = type('Avoid', (type(val),), {'__getitem__': _sub_getitem, 'pop': _sub_pop})(val)
    return val


class DefaultDict(dict):
    def __getitem__(self, k):
        return _sub_getitem(self, k)

    def pop(self, k):
        return _sub_pop(self, k)

In[8]: d=DefaultDict({'balabala':"dddddd"})
In[9]: d['a']['b']['c']['d']
Out[9]: ''
In[10]: d['a']="ggggggg"
In[11]: d['a']
Out[11]: 'ggggggg'
In[12]: d['a']['pp']
Out[12]: ''

再次没有错误。 无论嵌套多少级。 弹出也没有错误 您可以根据需要将其更改为任何值。