In Python, to make a shallow and deep copy, use the copy() method of lists list, dictionaries dict, etc., or the copy() and deepcopy() functions of the copy module.

This article describes the following contents.

  • Shallow copy and deep copy
  • Assignment to another variable
  • Shallow copy: copy()copy.copy(), etc.
    • copy() method of lists, dictionaries, etc.
    • Slice
    • list()dict(), etc.
    • copy.copy()
  • Deep copy: copy.deepcopy()

The following is a summary of the differences between assignment to another variable, shallow copy, and deep copy.

import copy  l = [0, 1, [2, 3]] l_assign = l                   # assignment l_copy = l.copy()              # shallow copy l_deepcopy = copy.deepcopy(l)  # deep copy  l[1] = 100 l[2][0] = 200 print(l) # [0, 100, [200, 3]]  print(l_assign) # [0, 100, [200, 3]]  print(l_copy) # [0, 1, [200, 3]]  print(l_deepcopy) # [0, 1, [2, 3]]

Shallow copy and deep copy

The explanation of shallow copy and deep copy in the official documentation is as follows.

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

For objects in mutable objects such as lists and dictionaries (= elements in a list or values in a dictionary), shallow copy inserts references and deep copy inserts copies. In the case of references, they are the same object, so if one of them is changed, the other will also be changed.

Assignment to another variable

First, let's see what happens when assigning to a variable.

When a mutable object such as a list or a dictionary is assigned to multiple variables, updating one variable (= changing, adding, or deleting elements, etc.) will also update the other variables.

l1 = [0, 1, [2, 3]] l2 = l1  print(l1 is l2) # True  l1[1] = 100 l1[2][0] = 200 print(l1) # [0, 100, [200, 3]]  print(l2) # [0, 100, [200, 3]]  print(l1 is l2) # True

As you can see from the result of is, the two variables refer to the same object both before and after the value is changed.

To create a copy instead of a reference of the same object, use the copy() method or the copy.deepcopy() function described below.

On the other hand, in the case of immutable objects such as numbers intfloat and strings str, the value of the object cannot be updated. When assigned, the two variables are the same object, but when one is updated to a new value, it becomes a different object and the other remains the same.

i1 = 1 i2 = i1  print(i1 is i2) # True  i1 += 100 print(i1) # 101  print(i2) # 1  print(i1 is i2) # False

Shallow copy: copy()copy.copy(), etc.

copy() method of lists, dictionaries, etc.

The copy() method is provided for lists, dictionaries, etc. The copy() method makes a shallow copy.

As mentioned above, a shallow copy inserts a reference to an object in the original object. For example, in the case of a shallow copy of a list, the list itself will be a different object, but its elements are references to the same objects in the elements of the original list.

l = [0, 1, [2, 3]] l_copy = l.copy()  print(l is l_copy) # False  print(l[2] is l_copy[2]) # True

Therefore, if the elements are mutable, when one is updated, the other is also updated. In the case of an immutable, when it is updated to a new value, it becomes a different object, and the other remains the original.

l[1] = 100 l[2][0] = 200 print(l) # [0, 100, [200, 3]]  print(l_copy) # [0, 1, [200, 3]]  print(l[2] is l_copy[2]) # True

The same applies not only to lists of lists as in the example above, but also to lists of dictionaries, nested dictionaries (dictionaries of dictionaries), etc.

Slice

Slices for mutable sequence types, such as lists, also make shallow copies.

For example, applying the slice [:] that specifies all elements makes a shallow copy of the whole list.

l = [0, 1, [2, 3]] l_whole_slice = l[:]  l[1] = 100 l[2][0] = 200 print(l) # [0, 100, [200, 3]]  print(l_whole_slice) # [0, 1, [200, 3]]

Since the copy() method was added to mutable sequence types in Python 3.3, the technique of making a shallow copy with [:] was used before that. For new code, it would be better to use the copy() method to make your intentions clearer.

A slice for a part also makes a shallow copy.

l = [0, 1, [2, 3]] l_slice = l[1:] print(l_slice) # [1, [2, 3]]  l[1] = 100 l[2][0] = 200 print(l) # [0, 100, [200, 3]]  print(l_slice) # [1, [200, 3]]

If you want to make a deep copy, you can apply the copy.deepcopy() function to the slice.

list()dict(), etc.

You can make a shallow copy of a list or dictionary by passing a list to list() or a dictionary to dict().

l = [0, 1, [2, 3]] l_list = list(l)  l[1] = 100 l[2][0] = 200 print(l) # [0, 100, [200, 3]]  print(l_list) # [0, 1, [200, 3]]

copy.copy()

It is also possible to make a shallow copy with the copy() function of the copy module.

l = [0, 1, [2, 3]] l_copy = copy.copy(l)  l[1] = 100 l[2][0] = 200 print(l) # [0, 100, [200, 3]]  print(l_copy) # [0, 1, [200, 3]]

Use copy.copy() if you want to make a shallow copy of an object for which the copy() method is not provided.

Deep copy: copy.deepcopy()

To make a deep copy, use the deepcopy() function of the copy module.

l = [0, 1, [2, 3]] l_deepcopy = copy.deepcopy(l)  print(l is l_deepcopy) # False  print(l[2] is l_deepcopy[2]) # False  l[1] = 100 l[2][0] = 200 print(l) # [0, 100, [200, 3]]  print(l_deepcopy) # [0, 1, [2, 3]]

In a deep copy, copies are inserted instead of references to objects, so changing one does not change the other.

The following is an example of applying the deepcopy() function to a slice.

l = [0, 1, [2, 3]] l_slice_deepcopy = copy.deepcopy(l[1:]) print(l_slice_deepcopy) # [1, [2, 3]]  l[1] = 100 l[2][0] = 200 print(l) # [0, 100, [200, 3]]  print(l_slice_deepcopy) # [1, [2, 3]]

Source:

https://note.nkmk.me/en/python-copy-deepcopy/