tags:

views:

53

answers:

2

Hi all,

I'm looking for a way to update dict dictionary1 with the contents of dict update wihout overwriting levelA

dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}}}
update={'level1':{'level2':{'levelB':10}}}
dictionary1.update(update)
print dictionary1
{'level1': {'level2': {'levelB': 10}}}

I know that update deletes the values in level2 because it's updating the lowest key level1.

How could I tackle this, given that dictionary1 and update can have any length?

+5  A: 

@FM's answer has the right general idea, i.e., a recursive solution, but somewhat peculiar coding and at least one bug. I'd recommend, instead:

import collections

def update(d, u):
    for k, v in u.iteritems():
        if isinstance(v, collections.Mapping):
            r = update(d.get(k, {}), v)
            d[k] = r
        else:
            d[k] = u[k]
    return d

The bug shows up when the "update" has a k, v item where v is a dict and k is not originally a key in the dictionary being updated -- @FM's code "skips" this part of the update (because it performs it on an empty new dict which isn't saved or returned anywhere, just lost when the recursive call returns).

My other changes are minor: there is no reason for the if/else construct when .get does the same job faster and cleaner, and isinstance is best applied to abstract base classes (not concrete ones) for generality.

Alex Martelli
+1 Good catch on the bug -- doh! I figured someone would would have a better way to handle the `isinstance` test, but thought I'd take a stab at it.
FM
Hi,This works as a charm, very elegant.I didn't know the existence of collections.Mapping very handy indeed.Thanks,Jay
jay_t
@jay_t. you're welcome -- yep, I agree that the collections' module abstract base classes (Mapping etc), which were new in Python 2.6, are really nice (you can also make your own ABCs with module abc!-).
Alex Martelli
A: 

That's a bit to the side but do you really need nested dictionaries? Depending on the problem, sometimes flat dictionary may suffice... and look good at it:

>>> dict1 = {('level1','level2','levelA'): 0}
>>> dict1['level1','level2','levelB'] = 1
>>> update = {('level1','level2','levelB'): 10}
>>> dict1.update(update)
>>> print dict1
{('level1', 'level2', 'levelB'): 10, ('level1', 'level2', 'levelA'): 0}
Nas Banov
The nested structure comes from incoming json datasets, so I would like to keep them intact,...
jay_t