问题:嵌套的defaultdict defaultdict
有没有办法使defaultdict也成为defaultdict的默认值?(即无限级递归defaultdict?)
我希望能够做到:
x = defaultdict(...stuff...)
x[0][1][0]
{}
因此,我可以做到x = defaultdict(defaultdict)
,但这仅是第二层:
x[0]
{}
x[0][0]
KeyError: 0
有一些食谱可以做到这一点。但是,仅使用常规的defaultdict参数就可以做到吗?
请注意,这是在问如何执行无限级递归defaultdict,因此它与Python不同:defaultdict的defaultdict?,这是执行两级defaultdict的方法。
我可能最终会使用束模式,但是当我意识到自己不知道该怎么做时,这引起了我的兴趣。
回答 0
对于任意数量的级别:
def rec_dd():
return defaultdict(rec_dd)
>>> x = rec_dd()
>>> x['a']['b']['c']['d']
defaultdict(<function rec_dd at 0x7f0dcef81500>, {})
>>> print json.dumps(x)
{"a": {"b": {"c": {"d": {}}}}}
当然,您也可以使用lambda来执行此操作,但是我发现lambda的可读性较差。无论如何,它看起来像这样:
rec_dd = lambda: defaultdict(rec_dd)
回答 1
这里的其他答案告诉您如何创建一个defaultdict
包含“无限多个”的defaultdict
,但是它们无法解决我认为您最初的需求,即仅具有两个深度的defaultdict。
您可能一直在寻找:
defaultdict(lambda: defaultdict(dict))
您可能更喜欢此构造的原因是:
- 它比递归解决方案更明确,因此读者可能更容易理解。
- 这使的“叶”
defaultdict
可以是除字典之外的其他内容,例如:defaultdict(lambda: defaultdict(list))
或defaultdict(lambda: defaultdict(set))
回答 2
有一个不错的技巧:
tree = lambda: defaultdict(tree)
然后,您可以使用创建自己x
的x = tree()
。
回答 3
与BrenBarn的解决方案类似,但是不包含tree
两次变量名,因此即使更改了变量字典也可以使用:
tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a))))
然后,您可以创建的每个新x
用x = tree()
。
对于该def
版本,我们可以使用函数闭包作用域来保护数据结构,以免其tree
名称被反弹时现有实例停止工作的缺陷。看起来像这样:
from collections import defaultdict
def tree():
def the_tree():
return defaultdict(the_tree)
return the_tree()
回答 4
我还将提出更多OOP样式的实现,该实现支持无限嵌套以及正确格式化repr
。
class NestedDefaultDict(defaultdict):
def __init__(self, *args, **kwargs):
super(NestedDefaultDict, self).__init__(NestedDefaultDict, *args, **kwargs)
def __repr__(self):
return repr(dict(self))
用法:
my_dict = NestedDefaultDict()
my_dict['a']['b'] = 1
my_dict['a']['c']['d'] = 2
my_dict['b']
print(my_dict) # {'a': {'b': 1, 'c': {'d': 2}}, 'b': {}}
回答 5
这是一个递归函数,用于将递归默认字典转换为普通字典
def defdict_to_dict(defdict, finaldict):
# pass in an empty dict for finaldict
for k, v in defdict.items():
if isinstance(v, defaultdict):
# new level created and that is the new value
finaldict[k] = defdict_to_dict(v, {})
else:
finaldict[k] = v
return finaldict
defdict_to_dict(my_rec_default_dict, {})
回答 6
我在这里基于安德鲁的答案。如果要从json或现有字典将数据加载到嵌套程序defaultdict中,请参见以下示例:
def nested_defaultdict(existing=None, **kwargs):
if existing is None:
existing = {}
if not isinstance(existing, dict):
return existing
existing = {key: nested_defaultdict(val) for key, val in existing.items()}
return defaultdict(nested_defaultdict, existing, **kwargs)
https://gist.github.com/nucklehead/2d29628bb49115f3c30e78c071207775