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日):

这个问题仍然没有答案。很明显,有“如何做我想做的事”的选项,但问题很简单:有“值”,我们把它传递给函数,函数修改它。看来这是不可能的。 只是一个值,没有任何“附加键”,等等。 如果是这样的话,我们能给出更一般的答案吗

注意事项:

  • 这个问题不是关于“在defaultdict中存储整数”,所以我不是在寻找一个在叶子上有int类型的defaultdict的层次结构
  • 假设类型(
    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))
  • 与(3)类似,但对于计数,您可以使用
    collections.Counter
    ,即
    d=defaultdict(Counter)
  • 如果你总是想达到设定的水平,我建议你选择第三或第四个选项。换句话说,标量值将仅在第n个级别提供,其中n是常量

    否则,一个手动选项是让功能执行型式试验。在这种情况下,
    尝试
    /
    ,但
    可能是一个不错的选择。在这里,我们还定义了一个递归算法,允许您提供一个键列表,而不是定义手动
    \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})})