2

I have a dictionary of settings of this kind of structure:

main_dict = {
    'a': {
        'a1': 1,
        'a2': 2,
    },
    'b': {
        'bb': {
            'bb1' : 1,
            'bb2' : 2,
        },
    },
}

I then have some classes which hold references to the dictionaries contained within main_dict, such as like this:

class B:
    def __init__(self, settings):
        self.settings = settings

my_b = B(main_dict['b'])
assert(my_b.settings is main_dict['b'])

So I can update the immutable values within main_dict and these updates will be reflected in my_b because my_b.settings is main_dict['b'].

However, I now have a new root dictionary with new settings in it following the same structure:

new_dict = {
    'a': {
        'a1': 11,
        'a2': 22,
    },
    'b': {
        'bb': {
            'bb1' : 11,
            'bb2' : 22,
        },
    },
}

Is there a simple and general purpose way to copy all of the immutable values in new_dict into main_dict such that the reference in my_b will be left intact?

Tim MB
  • 4,413
  • 4
  • 38
  • 48
  • @MartijnPieters , im pretty sure he wants to make sure the dictionary is the exact same. As in passing in by reference, not by value – TehTris May 24 '13 at 19:07
  • @TehTris: No, the OP wants to copy all nested dictionary values into an existing dictionary. You can do that by recursively updating, as shown in the other question. – Martijn Pieters May 24 '13 at 19:08
  • Is the shape (occurrences of dictionaries in the object graphs, and the sets of all dictionaries' keys) the same? –  May 24 '13 at 19:08
  • While my question is slightly more general than that question (I'm concerned with retaining the exact instances as well as preventing the loss of values in `main_dict` that aren't in `new_dict`), I think the answers given are fairly close to what's needed here. Thanks for finding it. – Tim MB May 24 '13 at 19:13
  • @delnan Not always, no. We may load an incomplete settings file, in which case some elements in `main_dict` would remain unupdated. (We may also have extra data in `new_dict` which would be inserted into `main_dict` – Tim MB May 24 '13 at 19:15
  • Having implemented hobs answer from the question @MartijnPieters cited I can confirm that it does solve my problem - for the case listed in the question at least. – Tim MB May 24 '13 at 20:01

1 Answers1

0

Would this help?

#!/usr/bin/env python3

def copyimmut(fromdict, todict):
    for key in fromdict:
        if type(fromdict[key]) is dict and key in todict:
            copyimmut(fromdict[key], todict[key])
        else:
            todict[key] = fromdict[key]

main_dict = {
    'a': {'a1': 1, 'a2': 2},
    'b': {'bb': {'bb1' : 1,'bb2' : 2, }}}

my_b = main_dict['b']
assert(my_b is main_dict['b'])
print(my_b)

new_dict = {
    'a': {'a1': 11, 'a2': 22},
    'b': {'bb': {'bb1' : 11, 'bb2' : 22, }},
    'c': {'cc': {'cc1' : 11, 'cc2' : 22, }}}

copyimmut(new_dict, main_dict)
assert(my_b is main_dict['b'])
print(my_b)
print(main_dict['c'])

yields

{'bb': {'bb1': 1, 'bb2': 2}}
{'bb': {'bb1': 11, 'bb2': 22}}
{'cc': {'cc2': 22, 'cc1': 11}}
uselpa
  • 18,732
  • 2
  • 34
  • 52
  • Thanks! Pretty much - however if you see http://stackoverflow.com/a/14048316/794283 , there is a boundary case that will cause problems if fromdict[key] is a dict but todict[key] is not. – Tim MB May 24 '13 at 19:54
  • Sure, I included no error checking or processing of edge cases, since I don't know which ones are bound to happen in your case. What should happen in the case you state? – uselpa May 24 '13 at 19:57
  • In this case, a new element would be created in main_dict – Tim MB May 24 '13 at 19:59
  • Thanks @uselpa, I think there is possibly one more edge case where fromdict[key] is a dict but todict[key] is not a dict that needs seeing - but it's clear enough to see how to do this. Recursion ftw - it's simpler than I was expecting ;) – Tim MB May 24 '13 at 21:58