特定类型的Python深度嵌套字典

特定类型的Python深度嵌套字典,python,dictionary,functools,Python,Dictionary,Functools,我想要一本深度嵌套的词典。让我们深思这一点。要显示什么,我需要一个5级字典,例如,foo[1][2][3][4][5],它将有一个集合或列表 正如我所见,我至少可以通过两种方式实现这一点: from collections import defaultdict foo = defaultdict(lambda: defaultdict(lambda:defaultdict(lambda: defaultdict(lambda: defaultdict(set))))) 或 然后在这两种情况下,

我想要一本深度嵌套的词典。让我们深思这一点。要显示什么,我需要一个5级字典,例如,
foo[1][2][3][4][5]
,它将有一个
集合
列表

正如我所见,我至少可以通过两种方式实现这一点:

from collections import defaultdict
foo = defaultdict(lambda: defaultdict(lambda:defaultdict(lambda: defaultdict(lambda: defaultdict(set)))))

然后在这两种情况下,我都可以,例如,
foo[1][2][3][4][5]。添加(1)

但我正在寻找一种不那么麻烦的方法来实现这一点,并找到了两种方法。第一个解决方案也在上述解决方案的同一位置提供:

class NestedDict(dict):
  def __getitem__(self, key):
    if key in self: return self.get(key)
    return self.setdefault(key, NestedDict())
第二个等价物是在这里找到的,作为一个关于自生问题的答案

class NestedDict(dict):
  """Implementation of perl's autovivification feature."""
  def __getitem__(self, item):
    try:
      print "__getitem__: %s" % item
      return dict.__getitem__(self, item)
    except KeyError:
      value = self[item] = type(self)()
      print "value: %s" % value
      return value
我喜欢最后两种方法,但我不知道如何更改它们以生成非dict的特定类型的嵌套字典,例如,
set
list
,这是通过
defaultdict
实现的


提前感谢您的任何建议、评论或更正。

此方法与您的第一个示例类似,只是您可以在无需大量键入的情况下指定所需的深度

from collections import defaultdict

def nested_default_dict(num_keys, init_func):
    if num_keys == 1:
        return defaultdict(init_func)
    else:
        return defaultdict(lambda: nested_default_dict(num_keys-1, init_func))

foo = nested_default_dict(5, set)
foo[1][2][3][4][5].add("Hello World")
foo[1][2][3][4][5].add("Lorem Ipsum")
foo[1][2][3][4][5].add("Dolor sit amet")
print foo[1][2][3][4][5]

bar = nested_default_dict(3, list)
bar[4][8][15].append(16)
bar[4][8][15].append(23)
bar[4][8][15].append(42)
print bar[4][8][15]
结果:

set(['Dolor sit amet', 'Lorem Ipsum', 'Hello World'])
[16, 23, 42]
一个缺点是,当你打印时,dicts看起来不是很漂亮:

>>>print foo
defaultdict(<function <lambda> at 0x0000000001FA8A58>, {1: defaultdict(<function <lambda> at 0x0000000001FAB198>, {2: defaultdict(<function <lambda> at 0x0000000001FAB208>, {3: defaultdict(<function <lambda> at 0x0000000001FAB278>, {4: defaultdict(<type 'set'>, {5: set(['Dolor sit amet', 'Lorem Ipsum', 'Hello World'])})})})})})
打印foo defaultdict(,{1:defaultdict(,{2:defaultdict(,{3:defaultdict(,{4:defaultdict(,{5:set(['Dolor sit amet','Lorem Ipsum','Hello World'])}})
这里有一个自动激活器,它不需要您设置默认工厂的级别。当您获得DefaultHasher上不存在的属性时,它会将自身更改为默认工厂的实例:

class DefaultHasher(dict):
    def __init__(self, default_factory, change_self=None):
        self.default_factory = default_factory
        self.change_self = change_self
    def change(self, key):
        def _change():
            x = self.default_factory()
            self[key] = x
            return x
        return _change
    def __missing__(self, key):
        self[key] = DefaultHasher(self.default_factory,
                                  self.change(key))
        return self[key]
    def __getattr__(self, name):
        result = self.change_self()
        return getattr(result, name)

foo = DefaultHasher(set)
foo[1][2][3][4][5].add(1)
print(foo)
# {1: {2: {3: {4: {5: set([1])}}}}}

foo[1][2][3].add(20)
print(foo)
# {1: {2: {3: set([20])}}}

foo[1][3] = foo[1][2]
print(foo)
# {1: {2: {3: set([20])}, 3: {3: set([20])}}}

foo[1][2].add(30)
print(foo)
# {1: {2: set([30]), 3: {3: set([20])}}}

“生成非dict的特定类型的嵌套字典”是什么意思?集合和列表不是字典;这句话对我来说毫无意义。是什么阻止你在你的自生字典中为一个键指定任意值?我相信他想要一个类似嵌套默认字典的东西。只有一个嵌套的字典,他不能做
foo[1][2][3][4][5]。添加(1)
,因为
foo[1][2][3][4][5]
计算为另一个嵌套的字典实例,他想要的不是布景,没有什么能阻止我这么做。我正在寻找一种不使用lambda或partial plus defaultdict的嵌套调用的方法。我正在寻找另一种方法。谢谢你的评论。@Bakuriu:谢谢你指出了这个咒语。我是Python新手,不知道。谢谢!这确实是解决我问题的办法。有趣的是,几分钟前我发现了这个解决方案:再次感谢!如果使用基本大小写0返回终端类型本身,则可以将其缩减为一行:
returndefaultdict((lambda:nested_default_dict(num_keys-1,init_func)If num_keys else init_func)
class DefaultHasher(dict):
    def __init__(self, default_factory, change_self=None):
        self.default_factory = default_factory
        self.change_self = change_self
    def change(self, key):
        def _change():
            x = self.default_factory()
            self[key] = x
            return x
        return _change
    def __missing__(self, key):
        self[key] = DefaultHasher(self.default_factory,
                                  self.change(key))
        return self[key]
    def __getattr__(self, name):
        result = self.change_self()
        return getattr(result, name)

foo = DefaultHasher(set)
foo[1][2][3][4][5].add(1)
print(foo)
# {1: {2: {3: {4: {5: set([1])}}}}}

foo[1][2][3].add(20)
print(foo)
# {1: {2: {3: set([20])}}}

foo[1][3] = foo[1][2]
print(foo)
# {1: {2: {3: set([20])}, 3: {3: set([20])}}}

foo[1][2].add(30)
print(foo)
# {1: {2: set([30]), 3: {3: set([20])}}}