Alex Alex - 2 months ago 11
Python Question

Recursive diff of two python dictionaries (keys and values)

So I have a python dictionary, call it

d1
, and a version of that dictionary at a later point in time, call it
d2
. I want to find all the changes between
d1
and
d2
. In other words, everything that was added, removed or changed. The tricky bit is that the values can be ints, strings, lists, or dicts, so it needs to be recursive. This is what I have so far:

def dd(d1, d2, ctx=""):
print "Changes in " + ctx
for k in d1:
if k not in d2:
print k + " removed from d2"
for k in d2:
if k not in d1:
print k + " added in d2"
continue
if d2[k] != d1[k]:
if type(d2[k]) not in (dict, list):
print k + " changed in d2 to " + str(d2[k])
else:
if type(d1[k]) != type(d2[k]):
print k + " changed to " + str(d2[k])
continue
else:
if type(d2[k]) == dict:
dd(d1[k], d2[k], k)
continue
print "Done with changes in " + ctx
return


It works just fine unless the value is a list. I cant quite come up with an elegant way to deal with lists, without having a huge, slightly changed version of this function repeated after a
if(type(d2) == list)
.

Any thoughts?

EDIT: This differs from this post because the keys can change

Answer

One option would be to convert any lists you run into as dictionaries with the index as a key. For example:

# add this function to the same module
def list_to_dict(l):
    return dict(zip(map(str, range(len(l))), l))

# add this code under the 'if type(d2[k]) == dict' block
                    elif type(d2[k]) == list:
                        dd(list_to_dict(d1[k]), list_to_dict(d2[k]), k)

Here is the output with the sample dictionaries you gave in comments:

>>> d1 = {"name":"Joe", "Pets":[{"name":"spot", "species":"dog"}]}
>>> d2 = {"name":"Joe", "Pets":[{"name":"spot", "species":"cat"}]}
>>> dd(d1, d2, "base")
Changes in base
Changes in Pets
Changes in 0
species changed in d2 to cat
Done with changes in 0
Done with changes in Pets
Done with changes in base

Note that this will compare index by index, so it will need some modification to work well for list items being added or removed.

Comments