Python 如何增加值(在defaultdict的defaultdict中)?
如果Python 如何增加值(在defaultdict的defaultdict中)?,python,dictionary,recursion,defaultdict,Python,Dictionary,Recursion,Defaultdict,如果d是defaultdict的defaultdict而没有代码重复,如何增加d['a']['b']['c'][1][2][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
d
是defaultdict
的defaultdict
而没有代码重复,如何增加d['a']['b']['c'][1][2][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
在这里,我们可以看到我们复制了(在代码中)一个键链3次
问题:是否可以编写一个函数inc
,该函数将采用嵌套的dict['a']['b']…[6]
,并执行与上述相同的工作?因此:
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
更新(2018年8月20日):
这个问题仍然没有答案。很明显,有“如何做我想做的事”的选项,但问题很简单:有“值”,我们把它传递给函数,函数修改它。看来这是不可能的。
只是一个值,没有任何“附加键”,等等。
如果是这样的话,我们能给出更一般的答案吗
注意事项:
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
为:
class Int:
def __init__(self, value):
self.value = value
def __add__(self, v):
self.value += v
return self
def __repr__(self):
return str(self.value)
这并不完全是易变的,更多的是关于赋值如何执行名称绑定
当您在inc
函数中执行x=0
时,您将一个新对象绑定到名称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})
q
现在指的是嵌套的dict['a']['b']['c']['d'][1][2][3][4][5]
不能有多个默认类型使用defaultdict
。您有以下选项:
defaultdict
对象的defaultdict
李>
int
对象的defaultdict
,这可能不适合您的需要李>
defaultdict
的defaultdict
下降到一个特定级别,最后一个级别定义了int
,例如,对于单个嵌套,d=defaultdict(lambda:defaultdict(int))
李>
collections.Counter
,即d=defaultdict(Counter)
尝试
/,但
可能是一个不错的选择。在这里,我们还定义了一个递归算法,允许您提供一个键列表,而不是定义手动\uuu getitem\uuu
调用
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})})
请不要在问题上同时使用python-3和python-2标记。如果你问的是特定于版本的问题,只能使用特定于版本的标签。我不知道为什么这个问题会被否决。这可能是误导,但这更是提供合理答案的理由。这似乎很清楚。考虑到至少有两个答案独立地理解了类似的想法。请为混乱和长键感到抱歉!我人为地这样做是为了让你感觉到,不通过代码分割所有的“a”、“b”、“c”等等是多么重要——请参阅下面我对其中一个答案的评论。(答案很好,但如果您有任何想法如何做到“只在一个地方提到它们的键”,我还是很高兴的)。如果我混淆了您的python版本,也很抱歉标记错误!您可能会发现这篇文章很有帮助:,这篇文章是由经验丰富的Ned Batchelder撰写的。感谢您的回答,如果示例混乱,请大家接受我的道歉,但这是有原因的。在您的示例中,您人为地打破了“钥匙链”。想象一下,我们必须将数据[星球][地区][城市]合并。在您的例子中,“first to keys”将转到“d”,最后一个键将转到inc的第二个参数。因此链在代码中分为两个位置。你认为:我们能避免它吗?并将“数据中的最终目的地”仅放在一个地方一次。再次提前感谢您的回答@请注意,“链条”只在一个地方分开。我们需要像这样分割它,因为我们想要改变作为
inc
的第一个参数传递的对象。在Python中没有其他(理智的)方法可以做到这一点。我也在考虑这一点!但为什么没有办法呢?我觉得我碰到了一些奇怪的东西,因为在其他语言中,使用内存管理/指针可以非常简单。也许有一些装饰师可以达成协议?@Pleeea是的,如果Python有指针的话,这将是直接的。但它不是故意的。:)Python的数据模型与类C语言的数据模型大不相同。一开始,当它不允许您以使用这些语言的方式进行操作时,这可能会让人恼火,但渐渐地,您会意识到Python方式的好处远远大于缺点。FWIW,在我学习Python之前,我已经用C编写了将近30年的代码。谢谢!我建议我们避免将讨论转移到“欣赏”和“利益”的问题上。你提到了模型是完全不同的:具体是怎样的?你能提供证据证明我所问的这些事情是不可能的吗?我不是在施压
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})})