Search code examples
pythondictionarynested

Nested dicts in python - assigning data


I need to created dict which handle defferent settings, depends on device (this settings are covered with dicts). For example: S1 - settings1, S2 - settings2. Under Sx settigs i have definition about channels parameters and other things. Channels parameters here are also dicts.

Why i can't assign dict with different lenght. It is hard to explain that with words, but looking into below code it should be clear what i want to achive:

main = ['S1', 'S2']
my_dict = dict.fromkeys(main, {})

CHANNELS_S1 = {'CH1': {'Unit': 'A', 'RANGE': '0.2'},
               'CH2': {'Unit': 'B', 'RANGE': '0.3'},
               'CH3': {'Unit': 'C', 'RANGE': '0.4'}}

CHANNELS_S2 = {'CH1': {'Unit': 'X', 'RANGE': '.2'}}


my_dict['S1']['CHANNELS'] = CHANNELS_S1
my_dict['S2']['CHANNELS'] = CHANNELS_S2

after running this i receiving:

{'S1': {'CHANNELS': {'CH1': {'Unit': 'X', 'RANGE': '.2'}}},
 'S2': {'CHANNELS': {'CH1': {'Unit': 'X', 'RANGE': '.2'}}}}

but i want to receive this:

{'S1': {'CHANNELS': {'CH1': {'Unit': 'A', 'RANGE': '0.2'},
                     'CH2: {'Unit': 'B', 'RANGE': '0.3'},
                     'CH3': {'Unit': 'C', 'RANGE': '0.4'}}},
 'S2': {'CHANNELS': {'CH1': {'Unit': 'X', 'RANGE': '.2'}}}}

Solution

  • Your default dict is shared:

    my_dict = dict.fromkeys(main, {})
    
    >>> id(my_dict['S1'])
    139825319264128
    
    >>> id(my_dict['S2'])
    139825319264128
    

    So each time you modify one the other is modified because this is the same memory location.

    You can use a dict comprehension:

    my_dict = {x: {} for x in main}
    
    my_dict['S1']['CHANNELS'] = CHANNELS_S1
    my_dict['S2']['CHANNELS'] = CHANNELS_S2
    
    >>> my_dict
    {'S1': {'CHANNELS': {'CH1': {'Unit': 'A', 'RANGE': '0.2'},
       'CH2': {'Unit': 'B', 'RANGE': '0.3'},
       'CH3': {'Unit': 'C', 'RANGE': '0.4'}}},
     'S2': {'CHANNELS': {'CH1': {'Unit': 'X', 'RANGE': '.2'}}}}
    

    From the documentation

    fromkeys() is a class method that returns a new dictionary. value defaults to None. All of the values refer to just a single instance, so it generally doesn’t make sense for value to be a mutable object such as an empty list. To get distinct values, use a dict comprehension instead.