Create Independent Copy of Nested List in Python

1 Introduction

In this blog post, I want to share my experience of how to create an independent copy of a Python list. Python provides various methods for copying lists, but not all of them create independent copies, especially when dealing with nested lists.

I will demonstrate the issues with list.copy() and the slice assignment [:], and then present a solution using the deepcopy function from the copy module.

2 The Problem with list.copy()

In Python, we must be cautious when using the assignment operator = to copy lists, as it creates a reference to the original list rather than an independent copy. This means that any modifications made to the copied list will affect the original list, and vice versa.

Let's examine an example using list.copy() and see its limitations:

1
2
3
4
5
6
7
8
9
10
11
12
13
A1 = [[1,2,3], [4,5,6], [7,8,9]]
print(A1)
#[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

B1 = A1.copy()
# same as B1 = A1[:]
B[0][0] = 3

print(B1)
# [[3, 2, 3], [4, 5, 6], [7, 8, 9]]

print(A1)
# [[3, 2, 3], [4, 5, 6], [7, 8, 9]]

As you can see, A1 changes as B1 changes. The same issue arises when using slice assignment [:].

However, if you are working on another list A2, list.copy() works.

1
2
3
4
5
6
7
8
A2 = [1,2,3]
B2 = A2.copy()
B2[0] = 3
print(B2)
#[3, 2, 3]

print(A2)
#[1, 2, 3]

Why? The answer is that list.copy() and newlist = oldlist[:] fail to produce independent copies of nested lists because they create shallow copies, preserving references to the original inner lists.

Then how can we copy it?

3 The Solution: Using deepcopy for Nested Lists

Python provides a useful function called deepcopy within the copy module.

The copy module's documentation distinguishes between two copy techniques: the deep copy and the shallow copy.

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

  • shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
  • deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

Back to the examples, the A1 list is a compound object, whereas the A2 list is not.

For an independent copy of the A1 list, a deep copy is required, whereas for the A2 list, a shallow copy suffices.

The commands list.copy() or newlist = oldlist[:] can be used to perform a shallow copy.

So the solution of the example is

1
2
3
4
5
6
7
8
9
10
11
import copy
A1 = [[1,2,3], [4,5,6], [7,8,9]]
print(A1)
# [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

B1 = copy.deepcopy(A1)
B1[0][0] = 3
print(B1)
# [[3, 2, 3], [4, 5, 6], [7, 8, 9]]
print(A1)
# [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Now, with deepcopy, B1 is a completely independent copy of A1, and any changes made to B1 will not affect A1.

4 Create Independent Copy of Lists

In summary, when dealing with nested lists, use deepcopy to create independent copies. For non-nested lists, you can safely use shallow copy methods.

Deep copy:

  • B = copy.deepcopy(A)

Shallow copy:

  • B = A[:]
  • B = A.copy()
  • B = copy.copy(A)

5 Reference

https://stackoverflow.com/questions/2612802/how-do-i-clone-a-list-so-that-it-doesnt-change-unexpectedly-after-assignment

https://docs.python.org/3/library/copy.html