Home > Software engineering >  How to "dereference" a dictionary?
How to "dereference" a dictionary?

Time:12-16

(not sure how to best word the question title)

I have a situation similar to the following:

In [1]: t = {1:2}

In [2]: x = {'a' : t, 'b' : t}

In [3]: x
Out[3]: {'a': {1: 2}, 'b': {1: 2}}

In [4]: x['a'].update({1:4})

In [5]: x
Out[5]: {'a': {1: 4}, 'b': {1: 4}}

In [6]:

But the dictionary is more complex.

I would like to ensure that no elements of the dictionary are references to any other elements in the dictionary, so that I'm able to update sub-sections of it without affecting others.

Ideally I would like to have something similar to:

t = {1:2}
x = {'a' : t, 'b' : t}
x = f(x)
x['a'].update({1:4})
# x is now: {'a': {1: 4}, 'b': {1: 2}}

Edit - additional information

Previous test case wasn't deep enough.

def get_dict():
    d1 = {
        1.0: "something",
        2.0: "other",
    }
    d2 = {"z": d1}
    tst = {
        "main_key": {
            "x": d2,
            "y": d2,
        }
    }
    return tst

Using this function I have:

from copy import deepcopy 
tst = get_dict()
tst = deepcopy(tst)
tst["main_key"]["x"].update({1: "check"})

Which outputs:

{'main_key': {'x': {1: 'check', 'z': {1.0: 'something', 2.0: 'other'}},
              'y': {1: 'check', 'z': {1.0: 'something', 2.0: 'other'}}}}

Rather than the expected:

{'main_key': {'x': {1: 'check', 'z': {1.0: 'something', 2.0: 'other'}},
              'y': {1: 'something', 'z': {1.0: 'something', 2.0: 'other'}}}}

CodePudding user response:

To simplify, when you do b = deepcopy(a), that means that nested dictionaries in b are not identical to the nested dictionaries in a, but it doesn't break the internal structure. Dictionaries accessible via different keys are still identical, and cyclical dictionaries (for example a[some_key] is a) remain cyclical.

The best way to deal with this is to make sure your dictionary doesn't have any unwanted shared references in the first place, for example by doing:

    return {
        "main_key": {
            "x": d2,
            "y": deepcopy(d2),
        }
    }

But if you don't control the way the data arrives, you could use a recursive function like this one:

def copy_tree(original):
    '''Creates a deep copy of a dictionary, but the copy will
    be a tree, so no shared references. Cyclic dictionaries will
    cause a recursion error.
    All keys, and all non-dictionary values are not copied but used
    as-is.'''
    if isinstance(original, dict):
        return {key: copy_tree(value) for key, value in original.items()}
    return original

CodePudding user response:

You can use .copy() on t.

t = {1:2}
x = {'a' : t.copy(), 'b' : t.copy()}
print(x) #{'a': {1: 2}, 'b': {1: 2}}
x['a'].update({1:4})
print(x) #{'a': {1: 4}, 'b': {1: 2}}

CodePudding user response:

You can create a new copy of the dictionary using deepcopy from copy:

from copy import deepcopy
x = deepcopy(x)
x['a'].update({1: 4})
#x: {'a': {1: 4}, 'b': {1: 4}}
#t: {1: 2}
  • Related