Search code examples
pythondefaultdict

Python Defaultdict with defined dictionary as default value shares the same dictionary between keys


I create a nested defaultdict within a defaultdict which I intend to have defined key:value pairs as the default value:

from collections import defaultdict
counter_format = {"correct": 0, "incorrect": 0}
userDict = defaultdict(lambda: defaultdict(lambda: counter_format))

however, updating individual keys within the dictionary within the nested defaultdicts causes this behavior:

userDict['a'][1]['correct']+=1

userDict['b'][1]['correct']+=1

userDict['b'][2]['correct']+=1

userDict now looks like:

defaultdict(<function <lambda> at 0x10ca85ee0>,
            {'a': defaultdict(<function <lambda>.<locals>.<lambda> at 0x10cbc0430>,
                              {1: {'correct': 3,
                                   'incorrect': 0}}),
             'b': defaultdict(<function <lambda>.<locals>.<lambda> at 0x10cbc0b80>,
                              {1: {'correct': 3,
                                   'incorrect': 0},
                               2: {'correct': 3,
                                   'incorrect': 0}})})

Solution

  • To fix this, you simply need to move your counter_format dictionary construction into the lambda, so that a new counter_format dictionary is created each time you try to access a missing value in your innermost defaultdict

    from collections import defaultdict
    
    userDict = defaultdict(lambda: 
        defaultdict(lambda: {"correct": 0, "incorrect": 0})
    )
    
    userDict['a'][1]['correct']+=1
    userDict['b'][1]['correct']+=4
    userDict['b'][2]['correct']+=1
    
    print(userdict)
    defaultdict(<function <lambda> at 0x7f0f6cb38550>,
                {'a': defaultdict(<function <lambda>.<locals>.<lambda> at 0x7f0f679424c0>,
                                  {1: {'correct': 1, 'incorrect': 0}}),
                 'b': defaultdict(<function <lambda>.<locals>.<lambda> at 0x7f0f4caaa430>,
                                  {1: {'correct': 4, 'incorrect': 0},
                                   2: {'correct': 1, 'incorrect': 0}})})