我该如何将嵌套字典转换为嵌套的defaultdict?
dic = {"a": {"aa": "xxx"}}
default = defaultdict(lambda: None, dic)
print(default["dummy_key"]) # return None
print(default["a"]["dummy_key"]) # KeyError
我该如何将嵌套字典转换为嵌套的defaultdict?
dic = {"a": {"aa": "xxx"}}
default = defaultdict(lambda: None, dic)
print(default["dummy_key"]) # return None
print(default["a"]["dummy_key"]) # KeyError
你需要在嵌套字典中循环或递归,遍历其所有级别。
除非它可能非常深层(如数百个级别),或者非常宽而小的性能因素会产生巨大影响,否则递归在这里可能是最简单的方法:
def defaultify(d):
if not isinstance(d, dict):
return d
return defaultdict(lambda: None, {k: defaultify(v) for k, v in d.items()})
如果您希望它适用于所有映射,而不仅仅是字典,您可以在isinstance
检查中使用collections.abc.Mapping
而不是dict
。def defaultify(d):
if isinstance(d, dict):
return defaultdict(lambda: None, {k: defaultify(v) for k, v in d.items()})
elif isinstance(d, list):
return [defaultify(e) for e in d]
else:
return d
如果这实际上是来自JSON的数据,最好在解析JSON时将您的defaultdict
作为object_pairs_hook
使用,而不是将其解析为字典,然后稍后再转换为defaultdict
。
文档中有一个使用OrderedDict
替换dict
的示例,但对我们来说不太适用——与OrderedDict
和dict
不同,defaultdict
不能仅将可迭代的键值对作为其唯一参数;首先需要默认值工厂函数。因此,我们可以使用functools.partial
绑定它:
d = json.loads(jsonstring, object_hook_pairs=partial(defaultdict, lambda: None))
< hr >
等等。
json.loads
或类似的方法中获取这个数据,那么你可能想考虑一开始就将其构建为一个defaultdict
,而不是先构建一个dict
再进行转换。例如,json
文档解释了如何使解码器对每个JSON对象使用OrderedDict
而不是dict
,你可以做同样的事情来使用defaultdict
。 - abarnertdefaultdict
,因为它需要一个额外的第一个参数。但是你可以使用例如functools.partial(defaultdict, lambda: None)
或者lambda *args, **kw: defaultdict(lambda: None, *args, **kw)
。我会将这个编辑到答案中。 - abarnertobject_hook_pairs
为object_pairs_hook
,但是出现了错误并发现了拼写错误。 - bergonzzi