特定类型的Python深度嵌套字典
我想要一本深度嵌套的词典。让我们深思这一点。要显示什么,我需要一个5级字典,例如,特定类型的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))))) 或 然后在这两种情况下,
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])}}}