Python中多个级别的“collection.defaultdict”
感谢一些伟大的人们,我发现了collections.defaultdict
提供的可能性,特别是在可读性和速度方面。 我已经把它们用于成功。
现在我想实现三个级别的字典,其中两个字典是defaultdict
,最低的是int
。 我没有find适当的方法来做到这一点。 这是我的尝试:
from collections import defaultdict d = defaultdict(defaultdict) a = [("key1", {"a1":22, "a2":33}), ("key2", {"a1":32, "a2":55}), ("key3", {"a1":43, "a2":44})] for i in a: d[i[0]] = i[1]
现在这是有效的,但是下面这个是所期望的行为,并不是:
d["key4"]["a1"] + 1
我怀疑我应该在某个地方声明第二层defaultdict
是int
types的,但我没有find在哪里或如何做。
我首先使用defaultdict
的原因是为了避免为每个新密钥初始化字典。
更优雅的build议?
感谢pythoneers!
使用:
d = defaultdict(lambda: defaultdict(int))
这将在d
访问新密钥时创build一个新的defaultdict(int)
。
另一种制作pickleable嵌套的defaultdict的方法是使用partial对象而不是lambda:
from functools import partial ... d = defaultdict(partial(defaultdict, int))
这将起作用,因为defaultdict类可以在模块级全局访问:
“你不能腌一个部分对象,除非函数[或在这种情况下,类]包装是全局可访问…在__name__下(在__module__中)” – 腌制包装的部分函数
在这里看看nosklo的答案是一个更一般的解决scheme。
class AutoVivification(dict): """Implementation of perl's autovivification feature.""" def __getitem__(self, item): try: return dict.__getitem__(self, item) except KeyError: value = self[item] = type(self)() return value
testing:
a = AutoVivification() a[1][2][3] = 4 a[1][3][3] = 5 a[1][2]['test'] = 6 print a
输出:
{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}
根据@ rschwieb对D['key'] += 1
的请求,我们可以通过定义__add__
方法来覆盖以前的扩展,使其更像一个collections.Counter()
首先__missing__
来创build一个新的空值,并将其传递给__add__
。 我们testing这个值,计算空值为False
。
有关覆盖的更多信息,请参阅模拟数字types 。
from numbers import Number class autovivify(dict): def __missing__(self, key): value = self[key] = type(self)() return value def __add__(self, x): """ override addition for numeric types when self is empty """ if not self and isinstance(x, Number): return x raise ValueError def __sub__(self, x): if not self and isinstance(x, Number): return -1 * x raise ValueError
例子:
>>> import autovivify >>> a = autovivify.autovivify() >>> a {} >>> a[2] {} >>> a {2: {}} >>> a[4] += 1 >>> a[5][3][2] -= 1 >>> a {2: {}, 4: 1, 5: {3: {2: -1}}}
而不是检查参数是一个数字(非非python,amirite!),我们可以提供一个默认的0值,然后尝试操作:
class av2(dict): def __missing__(self, key): value = self[key] = type(self)() return value def __add__(self, x): """ override addition when self is empty """ if not self: return 0 + x raise ValueError def __sub__(self, x): """ override subtraction when self is empty """ if not self: return 0 - x raise ValueError