defaultdict的嵌套defaultdict

Cor*_*man 109 python recursion defaultdict

有没有办法使defaultdict也成为defaultdict的默认值?(即无限级递归defaultdict?)

我希望能够做到:

x = defaultdict(...stuff...)
x[0][1][0]
{}
Run Code Online (Sandbox Code Playgroud)

所以,我可以这样做x = defaultdict(defaultdict),但那只是第二级:

x[0]
{}
x[0][0]
KeyError: 0
Run Code Online (Sandbox Code Playgroud)

有些食谱可以做到这一点.但是它可以简单地使用普通的defaultdict参数吗?

注意这是在询问如何进行无限级别的递归defaultdict,所以它与Python不同:defaultdict的defaultdict?,这是如何做一个两级默认.

我可能最终会使用模式,但当我意识到我不知道如何做到这一点时,它让我感兴趣.

And*_*ark 143

对于任意数量的级别:

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": {}}}}}
Run Code Online (Sandbox Code Playgroud)

当然你也可以用lambda来做这件事,但我觉得lambda不太可读.在任何情况下,它看起来像这样:

rec_dd = lambda: defaultdict(rec_dd)
Run Code Online (Sandbox Code Playgroud)

  • 我们如何定义字典底部最后一个值的类型? (4认同)
  • 确实是一个完美的例子,谢谢。您能否将其扩展到数据从 json 加载到 defaultdict 的 defaultdict 的情况? (3认同)
  • 一个说明.如果你试图使用这个代码,而酸洗`lambda`将无法正常工作. (3认同)

Chr*_* W. 138

这里的其他答案告诉你如何创建一个defaultdict包含"无限多"的内容defaultdict,但是它们无法解决我认为最初需要的问题,即只需要两个深度的默认值.

您可能一直在寻找:

defaultdict(lambda: defaultdict(dict))
Run Code Online (Sandbox Code Playgroud)

您可能更喜欢这种结构的原因是:

  • 它比递归解决方案更明确,因此读者可能更容易理解.
  • 这使得"叶子" defaultdict成为字典以外的东西,例如:defaultdict(lambda: defaultdict(list))defaultdict(lambda: defaultdict(set))

  • defaultdict(lambda:defaultdict(list))正确的形式? (3认同)
  • 这被标记为另一个问题的可能重复......但这不是我原来的问题.我知道如何创建一个两级默认用户; 我不知道的是如何使它递归.事实上,这个答案类似于http://stackoverflow.com/questions/5029934/python-defaultdict-of-defaultdict (3认同)

Bre*_*arn 41

这样做有一个很好的技巧:

tree = lambda: defaultdict(tree)
Run Code Online (Sandbox Code Playgroud)

然后你可以创建你xx = tree().

  • 这太棒了! (3认同)
  • 回到这一点,我认为这是我使用得最多的一段代码:) (2认同)

pts*_*pts 20

与BrenBarn的解决方案类似,但不包含变量的名称tree两次,因此即使在更改变量字典后也能正常工作:

tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a))))
Run Code Online (Sandbox Code Playgroud)

然后你可以创建每个新xx = tree().


对于def版本,我们可以使用函数闭包范围来保护数据结构免受现有实例在tree名称反弹时停止工作的缺陷的影响.它看起来像这样:

from collections import defaultdict

def tree():
    def the_tree():
        return defaultdict(the_tree)
    return the_tree()
Run Code Online (Sandbox Code Playgroud)

  • 我将不得不考虑这个(它有点复杂).但我认为你的观点是,如果做x = tree(),但是后来有人来,并且树=无,这个仍然可以工作,那不会吗? (4认同)

小智 6

我还将提出更多OOP样式的实现,该实现支持无限嵌套以及正确格式化repr

class NestedDefaultDict(defaultdict):
    def __init__(self, *args, **kwargs):
        super(NestedDefaultDict, self).__init__(NestedDefaultDict, *args, **kwargs)

    def __repr__(self):
        return repr(dict(self))
Run Code Online (Sandbox Code Playgroud)

用法:

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': {}}
Run Code Online (Sandbox Code Playgroud)

  • 整洁的 !我添加了“*args”和“**kwargs”的直通,这使得它可以像“defaultdict”一样运行,即创建一个带有关键字参数的字典。这对于将 `NestedDefaultDict` 传递到 `json.load` 很有用 (2认同)