mentby.com
Blog | Jobs | Help | Signup | Login

Is there a simple way to deep merge two dicts?  I'm looking for Perl's
Hash::Merge ( http://search.cpan.org/~dmuey/Hash-Merge-0.12/Merge.pm )
in Python.


Roy Smith Thu, 12 Apr 2012 10:49:05 -0700

def dmerge(a, b) :
    for k in a :
         v = a[k]
         if isinstance(v, dict) and k in b:
             dmerge(v, b[k])
    a.update(b)


John Nagle Thu, 12 Apr 2012 11:04:10 -0700

That doesn't work.  After b[k] is recursively merged into a[k], the
call "a.update(b)" copies b[k] into a[k], discarding the merged dict.
Try this:

def dmerge(a, b):
    for k, v in b.items():
        if isinstance(v, dict) and k in a:
            dmerge(a[k], v)
        else:
            a[k] = v

Hash::Merge also does a lot more than this, but I'm not sure exactly
which functionality the OP is looking for.
-- http://mail.python.org/mailman/listinfo/python-list


Ian Kelly Thu, 12 Apr 2012 11:39:40 -0700

There are a few problems with that code:
1) you don't make sure that b[k] is a dict so
        a={'a':{'b':1}}; b={'a':1}
    make it crash.
intended behavior.
For instance, with the 'a' and 'b' above, the result would be
     {'a':1}

Kiuhnm


Kiuhnm Thu, 12 Apr 2012 15:03:30 -0700

I think you also have to check if a[k] is a dict before making the recursive
call, else for example dmerge({'a': 1}, {'a': {'b': 1}}) fails with a
TypeError. In that case the third line above should read:

    if k in a and isinstance(a[k], dict) and isinstance(v, dict):

Regards,

John
--  http://mail.python.org/mailman/listinfo/python-list


John O'Hagan Fri, 13 Apr 2012 04:15:24 -0700

I guess it's reasonable that if a user wants to merge two dicts, the two dicts should have the same structure. This kind of thing I've used before to merge two logging config dictionaries:  https://docs.djangoproject.com/en/dev/topics/logging/#an-exa[..]


nbv4 Fri, 13 Apr 2012 09:28:15 -0700

Okay, but then what do you do in that case?  You can't merge a dict
into an int.  Unless the OP has some specific type conflict semantics
in mind, the above *should* raise a TypeError, because in the above
you have passed in two structures that are incompatible for merging.
-- http://mail.python.org/mailman/listinfo/python-list


Ian Kelly Fri, 13 Apr 2012 09:54:07 -0700

I had assumed it should work like dict.update, but deeply. Following the link
provided by the OP, I see your point: the merge function described there has
various precedence/conflict-handling options, of which my assumption is only
one. Another is to enforce the same nesting structure for both arguments, as
yours does.

As an aside, I'm not entirely clear on the distinction between merge and
update; for example, should a merge return a new object?

Regards,

John
--  http://mail.python.org/mailman/listinfo/python-list


John O'Hagan Fri, 13 Apr 2012 22:02:02 -0700



Related Topics

Post a Comment