Understanding dict.copy() - shallow or deep? Understanding dict.copy() - shallow or deep? python python

Understanding dict.copy() - shallow or deep?


By "shallow copying" it means the content of the dictionary is not copied by value, but just creating a new reference.

>>> a = {1: [1,2,3]}>>> b = a.copy()>>> a, b({1: [1, 2, 3]}, {1: [1, 2, 3]})>>> a[1].append(4)>>> a, b({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})

In contrast, a deep copy will copy all contents by value.

>>> import copy>>> c = copy.deepcopy(a)>>> a, c({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})>>> a[1].append(5)>>> a, c({1: [1, 2, 3, 4, 5]}, {1: [1, 2, 3, 4]})

So:

  1. b = a: Reference assignment, Make a and b points to the same object.

    Illustration of 'a = b': 'a' and 'b' both point to '{1: L}', 'L' points to '[1, 2, 3]'.

  2. b = a.copy(): Shallow copying, a and b will become two isolated objects, but their contents still share the same reference

    Illustration of 'b = a.copy()': 'a' points to '{1: L}', 'b' points to '{1: M}', 'L' and 'M' both point to '[1, 2, 3]'.

  3. b = copy.deepcopy(a): Deep copying, a and b's structure and content become completely isolated.

    Illustration of 'b = copy.deepcopy(a)': 'a' points to '{1: L}', 'L' points to '[1, 2, 3]'; 'b' points to '{1: M}', 'M' points to a different instance of '[1, 2, 3]'.


Take this example:

original = dict(a=1, b=2, c=dict(d=4, e=5))new = original.copy()

Now let's change a value in the 'shallow' (first) level:

new['a'] = 10# new = {'a': 10, 'b': 2, 'c': {'d': 4, 'e': 5}}# original = {'a': 1, 'b': 2, 'c': {'d': 4, 'e': 5}}# no change in original, since ['a'] is an immutable integer

Now let's change a value one level deeper:

new['c']['d'] = 40# new = {'a': 10, 'b': 2, 'c': {'d': 40, 'e': 5}}# original = {'a': 1, 'b': 2, 'c': {'d': 40, 'e': 5}}# new['c'] points to the same original['d'] mutable dictionary, so it will be changed


It's not a matter of deep copy or shallow copy, none of what you're doing is deep copy.

Here:

>>> new = original 

you're creating a new reference to the the list/dict referenced by original.

while here:

>>> new = original.copy()>>> # or>>> new = list(original) # dict(original)

you're creating a new list/dict which is filled with a copy of the references of objects contained in the original container.