Re: Deep merge two dicts?

2012-04-13 Thread John O'Hagan
On Thu, 12 Apr 2012 12:35:21 -0600
Ian Kelly ian.g.ke...@gmail.com wrote:

 On Thu, Apr 12, 2012 at 11:59 AM, John Nagle na...@animats.com wrote:
  On 4/12/2012 10:41 AM, Roy Smith wrote:
 
  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.
 
 
  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)
 
 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
 

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


Re: Deep merge two dicts?

2012-04-13 Thread nbvfour
On Thursday, April 12, 2012 5:54:47 PM UTC-4, Kiuhnm wrote:
 On 4/12/2012 19:59, John Nagle wrote:
  On 4/12/2012 10:41 AM, Roy Smith wrote:
  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.
 
  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)
 
 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.
 2) the last update overwrites nested updates, but this could be the 
 intended behavior.
 For instance, with the 'a' and 'b' above, the result would be
  {'a':1}
 
 Kiuhnm

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-example
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Deep merge two dicts?

2012-04-13 Thread Ian Kelly
On Fri, Apr 13, 2012 at 5:11 AM, John O'Hagan resea...@johnohagan.com wrote:
 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):

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


Re: Deep merge two dicts?

2012-04-13 Thread John O'Hagan
On Fri, 13 Apr 2012 10:50:15 -0600
Ian Kelly ian.g.ke...@gmail.com wrote:

 On Fri, Apr 13, 2012 at 5:11 AM, John O'Hagan resea...@johnohagan.com wrote:
  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):
 
 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.

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


Deep merge two dicts?

2012-04-12 Thread Roy Smith
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.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Deep merge two dicts?

2012-04-12 Thread John Nagle

On 4/12/2012 10:41 AM, Roy Smith wrote:

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.


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)



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


Re: Deep merge two dicts?

2012-04-12 Thread Ian Kelly
On Thu, Apr 12, 2012 at 11:59 AM, John Nagle na...@animats.com wrote:
 On 4/12/2012 10:41 AM, Roy Smith wrote:

 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.


 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)

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


Re: Deep merge two dicts?

2012-04-12 Thread Kiuhnm

On 4/12/2012 19:59, John Nagle wrote:

On 4/12/2012 10:41 AM, Roy Smith wrote:

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.


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)


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.
2) the last update overwrites nested updates, but this could be the 
intended behavior.

For instance, with the 'a' and 'b' above, the result would be
{'a':1}

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