'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 1:[1]

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}})})



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Cameron Riddell