Denis Gantsev Denis Gantsev - 1 year ago 82
Python Question

merging dicts not working as expected python 3.5

This is Python 3.5 environment, I think the code is self explanatory, here it is, I am expecting both functions to work, but only one is correct.

TLDR:
Assigning

out = {**out, **answer}
makes
out
variable containing right keys, but they are lost during the next 2 steps; while assigning
c = {**c,**a}
works perfectly in test function, and new keys are not lost.

Could someone please explain what I am doing wrong?

def flatify_works(d, out, fhook=None):
for k, v in d.items():
if not isinstance(v, dict) and not isinstance(v, list):
out[k] = v
elif isinstance(v, dict):
flatify_works(v, out, fhook)
elif isinstance(v, list):
if fhook is None:
raise AssertionError("an array with more than 1 elment found.")
answer = fhook(k, v)
for k, v in answer.items():
out[k] = v


def flatify_doesnt_work(d, out, fhook=None):
for k, v in d.items():
if not isinstance(v, dict) and not isinstance(v, list):
out[k] = v
elif isinstance(v, dict):
flatify_doesnt_work(v, out, fhook)
elif isinstance(v, list):
if fhook is None:
raise AssertionError("an array with more than 1 elment found.")
answer = fhook(k, v)
out = {**out, **answer} # put a breakpoint here, and go 2 steps further


def hook(k, v):
l = [d["c"] for d in v]
return {"c": sum(l), "d": "blabla"}


def test_merge_dicts():
a = {"a": 1, "b": 2}
c = {"c": 3}
c = {**c, **a} # merging works perfectly here
print(c)
assert "a" in c and "b" in c and "c" in c # ok


def test_nested_works():
out = {}
flatify_works({"a": 1, "b": [{"c": 0.6, "d": 4}, {"c": 0.4, "d": 4}]}, out, hook)
print("working exemple: {}".format(str(out)))


def test_nested_doesnt_work():
out = {}
flatify_doesnt_work({"a": 1, "b": [{"c": 0.6, "d": 4}, {"c": 0.4, "d": 4}]}, out, hook)
print("not working exemple: {}".format(str(out)))


def main():
test_merge_dicts() # ok
test_nested_works() # ok
test_nested_doesnt_work() # why out = {**out, **answer} is not working as expected?


if __name__ == '__main__':
main()

Answer Source

I think the difference is that in the second function, you reassign the out variable, after which it is detached from the dict that you pass into the function:

out = {**out, **answer} # out is now a different object

Since the function is recursive, the subsequent modifications do not affect the original dict.

In the first function, though, you only do item assignment, which modifies the dict in place, as expected:

out[k] = v
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download