Possible Duplicate:
python: Dictionaries of dictionaries merge
I'm keeping a bunch of app settings stored in a dictionary that is saved to a text file as JSON. I'd like to to merge it with a default set of key/values, so that as the app changes in the future, the new ones can be merged in. For example:
defaults = {
'svn': "",
'notify': {
'email': "",
'notifo': { 'username': "", 'secret': ""},
'active': False,
'lastCheck': 0
}
}
local = {
'svn': "/path/to/trunk/",
'notify': {
'email': "[email protected]",
'notifo': { 'username': "me", 'secret': "1234"},
}
}
Notice that 'local' is missing ['notify']['active'] and ['notify']['lastCheck']. I want to be able to merge the two dictionaries into one that looks like this:
local = {
'svn': "/path/to/trunk/",
'notify': {
'email': "[email protected]",
'notifo': { 'username': "me", 'secret': "1234"},
'active': False,
'lastCheck': 0
}
}
I've been looking everywhere but only see examples of people flattening the dictionaries, merging the first level or doing funny things with defaultdict. Is it possible to recursively merge nested dictionaries.
I think the following function might do what you want, but I've not checked all possible combinations of missing keys in each dictionary. Also, this is probably not optimized for large dicts:
import types
def merge(x,y):
# store a copy of x, but overwrite with y's values where applicable
merged = dict(x,**y)
xkeys = x.keys()
# if the value of merged[key] was overwritten with y[key]'s value
# then we need to put back any missing x[key] values
for key in xkeys:
# if this key is a dictionary, recurse
if type(x[key]) is types.DictType and y.has_key(key):
merged[key] = merge(x[key],y[key])
return merged
It appears to work on your example, plus a few extra items I added for complexity, by putting the merge function and the following bit in a file test.py:
defaults = {
'svn': "",
'notify': {
'email': "",
'notifo': { 'username': "", 'secret': ""},
'active': False,
'lastCheck': 0
},
'test': "another test"
}
local = {
'svn': "/path/to/trunk/",
'notify': {
'email': "[email protected]",
'notifo': { 'username': "me", 'secret': "1234", 'notx': 39},
},
'test2': 'again a test'
}
print merge(defaults,local)
and running gives:
$ python test.py
{'svn': '/path/to/trunk/', 'test2': 'again a test', 'notify': {'lastCheck': 0, 'notifo': {'username': 'me', 'secret': '1234', 'notx': 39}, 'active': False, 'email': '[email protected]'}, 'test': 'another test'}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With