如果d['a']['b']['c'][1][2][3]
是d
的{{1}}且没有代码复制,如何增加defaultdict
?
defaultdict
在这里我们可以看到我们(在代码中)重复了3次密钥链。
问题:是否可以编写一个函数from collections import defaultdict
nested_dict_type = lambda: defaultdict(nested_dict_type)
nested_dict = nested_dict_type()
# incrementation
if type(nested_dict['a']['b']['c']['d'][1][2][3][4][5][6]) != int:
nested_dict['a']['b']['c']['d'][1][2][3][4][5][6] = 0
nested_dict['a']['b']['c']['d'][1][2][3][4][5][6] += 1 # ok, now it contains 1
,该函数将采用inc
并完成与上述相同的工作?所以:
nested_dict['a']['b']...[6]
更新(2018年8月20日):
该问题仍然没有答案。很明显,有一些选项“如何做我想做的事”,但是问题很简单:存在“值”,我们将其传递给函数,函数对其进行修改。看来这是不可能的。 只是一个值,没有任何“附加键”等 如果是这样,我们可以使答案更通用吗?
注释:
def inc(x):
if type(x) != int:
x = 0
x += 1
inc(nested_dict['a']['b']['c']['d'][1][2][3][4][5][6]) # ok, now it contains 1
)事先已知/甚至可以参数化(包括执行int
运算符的能力)-问题是如何取消引用对象,将其传递进行修改并在defaultdict的defaultdict上下文中存储 。示例:
+=
def inc(x):
x += 1
d = {'a': int(0)}
inc(d['a'])
# d['a'] == 0, immutable
d = {'a': Int(0)}
inc(d['a'])
# d['a'] == 1, mutated
在哪里:
Int
答案 0 :(得分:2)
与不是完全而是可变性,更多关于赋值如何执行名称绑定。
在x = 0
函数中执行inc
时,会将新对象绑定到名称x
,并且该名称与绑定到该名称的先前对象之间的任何连接都将丢失。这不取决于x
是否可变。
但是由于x
是可变对象中的一项,我们可以通过将父可变对象以及访问所需项目所需的密钥传递给inc
来实现所需的目的。
from collections import defaultdict
nested_dict_type = lambda: defaultdict(nested_dict_type)
nested_dict = nested_dict_type()
# incrementation
def inc(ref, key):
if not isinstance(ref[key], int):
ref[key] = 0
ref[key] += 1
d = nested_dict['a']['b']['c']['d'][1][2][3][4][5]
inc(d, 6)
print(d)
输出
defaultdict(<function <lambda> at 0xb730553c>, {6: 1})
现在我们不绑定新对象,我们只是对现有对象进行突变,因此原始d
对象会正确更新。
顺便说一句,深层嵌套的字典使用起来有些痛苦。也许有一种更好的方法来组织数据……但是,无论如何,在使用深层嵌套时可以方便使用的一件事是使用列表或键元组。例如,
q = nested_dict
keys = 'a', 'b', 'c', 'd', 1, 2, 3, 4, 5
for k in keys:
q = q[k]
q
现在是指nested_dict['a']['b']['c']['d'][1][2][3][4][5]
答案 1 :(得分:1)
defaultdict
不能有多个默认类型。您有以下选择:
defaultdict
个对象中的defaultdict
个对象; defaultdict
个对象中的int
,可能不符合您的需求; defaultdict
中的defaultdict
降至特定级别,并为最后一个级别定义了int
,例如d = defaultdict(lambda: defaultdict(int))
用于单个嵌套; collections.Counter
,即d = defaultdict(Counter)
。如果您总是要下降到设定的水平,我建议使用第3或第4选项。换句话说,标量值将仅在第 n 个级别提供,其中 n 是恒定的。
否则,一个手动选项是让函数执行类型测试。在这种情况下,try
/ except
可能是一个很好的选择。在这里,我们还定义了一种递归算法,使您可以提供键列表而不是定义手动__getitem__
调用。
from collections import defaultdict
from functools import reduce
from operator import getitem
nested_dict_type = lambda: defaultdict(nested_dict_type)
d = nested_dict_type()
d[1][2] = 10
def inc(d_in, L):
try:
reduce(getitem, L[:-1], d_in)[L[-1]] += 1
except TypeError:
reduce(getitem, L[:-1], d_in)[L[-1]] = 1
inc(d, [1, 2])
inc(d, [1, 3])
print(d)
defaultdict({1: defaultdict({2: 11, 3: 1})})