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

时间:2013-07-12 12:43:55

标签: python dictionary functools

我想要一个字典深度嵌套。让我们考虑“深入”。要显示我需要的5级字典,例如,foo[1][2][3][4][5]set作为项目。{/ p>

正如我所看到的那样here我至少可以通过两种方式实现这一目标:

list

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

然后在两种情况下我都可以from functools import partial foo = defaultdict(partial(defaultdict, partial(defaultdict, partial(defaultdict, partial(defaultdict, set)))))

但我一直在寻找一种不那么繁琐的方法来实现这一目标,并找到了两种方法。第一个也提供与上述解决方案相同的地方:

foo[1][2][3][4][5].add(1)

和第二个等价物在此处作为answer在自动回复问题中找到。

class NestedDict(dict):
  def __getitem__(self, key):
    if key in self: return self.get(key)
    return self.setdefault(key, NestedDict())

我喜欢最后两种方法,但我不知道如何更改它们以生成不是dict的特定类型的嵌套字典,例如,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 set已完成与list

提前感谢任何建议,评论或更正。

2 个答案:

答案 0 :(得分:1)

这种方法类似于你的第一个例子,除了你可以指定任何你想要的深度,而无需大量输入。

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]

一个缺点是当你打印它们时,它们看起来不太漂亮:

>>>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'])})})})})})

答案 1 :(得分:1)

这是一个自动复制程序,它不需要您设置默认工厂的级别。当您获得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])}}}