Home > Enterprise >  KeyError while defining a new key value pair in a defaultdict created from an existing dictionary
KeyError while defining a new key value pair in a defaultdict created from an existing dictionary

Time:07-19

Below is a sample code:

from collections import defaultdict

normal_dict = {
    "test": {
        "test1": 1,
        "test2": 2,
        "test3": {
            "test3_1": 1
        }
    }
}

default_dict = defaultdict(lambda: defaultdict(dict), normal_dict)

default_dict['test']['test4']['test4_1'] = 1 # Doesn't work


print(default_dict)

I get this error

Traceback (most recent call last):
  File "<string>", line 17, in <module>
KeyError: 'test4'

It seems like the previously non-existent key 'test4' is not being automatically added when I use the line default_dict['test']['test4']['test4_1'], for some reason. Theoretically, defaultdict should create the key test4 with another defaultdict as its default value.

CodePudding user response:

The Problem

The problem is that:

default_dict['test']

is:

{'test1': 1, 'test2': 2, 'test3': {'test3_1': 1}}

in other words is a dictionary not a defaultdict. Note that defaultdict provides a value (through the factory method) for a missing key, which is not the case at creation time in:

default_dict = defaultdict(lambda: defaultdict(dict), normal_dict)

It won't copy the values and "transform" them to defaultdict.

One solution

One approach, that transform every nested dictionary into a defaultdict is the following:

def nested_dd():
    # https://stackoverflow.com/a/19189356/4001592
    return defaultdict(nested_dd)


def convert_to_default(d):
    res = nested_dd()
    for key, value in d.items():
        if isinstance(value, dict):
            res[key] = convert_to_default(value)
        else:
            res[key] = value
    return res


result = convert_to_default(normal_dict)

result['test']['test4']['test4_1'] = 1
pprint.pprint(result)  # need to import pprint

Output

defaultdict(<function nested_dd at 0x7fd27008bd90>,
            {'test': defaultdict(<function nested_dd at 0x7fd27008bd90>,
                                 {'test1': 1,
                                  'test2': 2,
                                  'test3': defaultdict(<function nested_dd at 0x7fd27008bd90>,
                                                       {'test3_1': 1}),
                                  'test4': defaultdict(<function nested_dd at 0x7fd27008bd90>,
                                                       {'test4_1': 1})})})
  • Related