Welcome, guest | Sign In | My Account | Store | Cart

This function recursively walks the items and values of two dict like objects. At each level when a key exists in both, and each value is a dict, then the destination dict is updated from the source dict usiing the builtin dict.update method. After the operation all keys and values from the source, at any level, will be referenced in the destination.

Python, 72 lines
 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73``` ```def recursiveupdate(dst, src): """Recursively update dst from src. Recursion depth is bounded by the heap rather than the python interpretor recursion limit. >>> dst = dict(a=1,b=2,c=dict(ca=31, cc=33, cd=dict(cca=1)), d=4, f=6) >>> src = dict(b='u2',c=dict(cb='u32', cd=dict(cda=dict(cdaa='u3411', cdab='u3412'))), e='u5') >>> r = recursiveupdate(dst, src) >>> assert r is dst >>> assert r['a'] == 1 and r['d'] == 4 and r['f'] == 6 >>> assert r['b'] == 'u2' and r['e'] == 'u5' >>> assert dst['c'] is r['c'] >>> assert dst['c']['cd'] is r['c']['cd'] >>> assert r['c']['cd']['cda']['cdaa'] == 'u3411' >>> assert r['c']['cd']['cda']['cdab'] == 'u3412' >>> from pprint import pprint; pprint(r) {'a': 1, 'b': 'u2', 'c': {'ca': 31, 'cb': 'u32', 'cc': 33, 'cd': {'cca': 1, 'cda': {'cdab': 'u3412', 'cdaa': 'u3411'}}}, 'd': 4, 'e': 'u5', 'f': 6} """ irecursiveupdate(dst, src.iteritems()) return dst def irecursiveupdate(a, biter): """Recursively update dict `a` from `biter` `biter` is assumed to be an iterable of the form:: [(k0, v0), (k1, v1), ..., (kN, vN)] ie, the result of src.iteritems() `a` is assumed to be a dict or dict like instance. In the following `dst` is the intial value of `a` and `src` is the initial value of `biter`. For every key in src: If that key is also in dst and both dst[k] and src[k] are dicts then: recursiveupdate(dst[k], (src[k])) otherwise: dst[k] = src[k] """ try: stack = [] while biter: for (bk,bv) in biter: if (bk in a and isinstance(bv, dict) and isinstance(a[bk], dict)): stack.append((biter, a)) # current -> parent break else: a[bk] = bv else: while not biter: biter, a = stack.pop() # current <- parent continue biter, a = bv.iteritems(), a[bk] except IndexError: pass if __name__ == '__main__': import doctest doctest.testmod() ```

A typical use of this recipe is for merging configuration, option and default value trees. Libraries like ConfgiObj support this sort of thing and a lot more besides. However, if all you want is a merge based on pythons dict.update semantics then this recipe may be all you need.

#### 1 comment

Manuel Muradas 14 years, 7 months ago

My version:

``````def merge_dictionary(dst, src):
stack = [(dst, src)]
while stack:
current_dst, current_src = stack.pop()
for key in current_src:
if key not in current_dst:
current_dst[key] = current_src[key]
else:
if isinstance(current_src[key], dict) and isinstance(current_dst[key], dict) :
stack.append((current_dst[key], current_src[key]))
else:
current_dst[key] = current_src[key]
return dst

if __name__ == '__main__':
dst = dict(a=1,b=2,c=dict(ca=31, cc=33, cd=dict(cca=1)), d=4, f=6, g=7)
src = dict(b='u2',c=dict(cb='u32', cd=dict(cda=dict(cdaa='u3411', cdab='u3412'))), e='u5', h=dict(i='u4321'))
r = merge_dictionary(dst, src)
assert r is dst
assert r['a'] == 1 and r['d'] == 4 and r['f'] == 6
assert r['b'] == 'u2' and r['e'] == 'u5'
assert dst['c'] is r['c']
assert dst['c']['cd'] is r['c']['cd']
assert r['c']['cd']['cda']['cdaa'] == 'u3411'
assert r['c']['cd']['cda']['cdab'] == 'u3412'
assert r['g'] == 7
assert src['h'] is r['h']

from pprint import pprint
pprint(r)
``````
 Created by Robin Bryce on Tue, 19 Dec 2006 (PSF)

### Tags

• (none)
▶ Show machine tags (5)