How to update just one key of python's nested dictionary?

Viewed 48

I run into a strange behavior of Python nested dictionaries. I want to update key var_set in nested dictionary when upper key is global. But it updates all var_set recursively even when upper key is foo and bar.

g = 'global'
s = set()
space = {g:
         {'parent': 'None', 'var_set': s, 'child_dict': {}
          }
         }

def create(child, parent, space):
    if parent in space.keys():
        space[parent]['child_dict'][child] = {
            'parent': parent, 'var_set': s, 'child_dict': {}}
    else:
        create(child, parent, space[g]['child_dict'])

def adding(parent, var, space):
    for (k, v) in space.items():
        if k == parent:
            v['var_set'].add(var)

create('foo', 'global', space)
create('bar', 'foo', space)
print(space)
adding(g, 'a', space)
print(space)

returns:

{'global': {'parent': 'None', 'var_set': set(), 'child_dict': {'foo': {'parent': 'global',
                                                                       'var_set': set(), 'child_dict': {'bar': {'parent': 'foo', 'var_set': set(), 'child_dict': {}}}}}}}
{'global': {'parent': 'None', 'var_set': {'a'}, 'child_dict': {'foo': {'parent': 'global',
                                                                       'var_set': {'a'}, 'child_dict': {'bar': {'parent': 'foo', 'var_set': {'a'}, 'child_dict': {}}}}}}}

Why all var_set updated recursively? I need just first one to be updated.

Well, let's copy the first result with empty sets and call adding against it too:

create('foo', 'global', space)
create('bar', 'foo', space)

lst = {'global': {'parent': 'None', 'var_set': set(), 'child_dict': {'foo': {'parent': 'global',
                                                                             'var_set': set(), 'child_dict': {'bar': {'parent': 'foo', 'var_set': set(), 'child_dict': {}}}}}}}

print(lst == space)
adding(g, 'a', lst)
adding(g, 'a', space)
print(lst)
print(space)

It returns:

True
{'global': {'parent': 'None', 'var_set': {'a'}, 'child_dict': {'foo': {'parent': 'global',
 'var_set': set(), 'child_dict': {'bar': {'parent': 'foo', 'var_set': set(), 'child_dict': {}}}}}}}
{'global': {'parent': 'None', 'var_set': {'a'}, 'child_dict': {'foo': {'parent': 'global',
                                                                       'var_set': {'a'}, 'child_dict': {'bar': {'parent': 'foo', 'var_set': {'a'}, 'child_dict': {}}}}}}}

They are equal and gives different results. Why such divergence? How to make it update just global's var_set and ignore foo's and bar's ones?

Update:

The problem is in declaring empty set globally for var_sets. They link to one object. Changing it once will change it for var_sets.

1 Answers

The problem is in declaring empty set globally for var_sets. They link to one object. Changing it once will change it for every var_sets.

Thanks to @jonrsharpe

Related