Python’s list type (part 3) — Shallow vs. deep copying
In part 3, we will learn
- Different types to copy a list
- Shallow copies vs. deep copies
Assignment to a list
Let’s consider the following example
x = [1, 2, 3]
y = x
From the article on variables, you know that x
and y
are now just two labels pasted on the same box (pointing to the same underlying object).
print(id(x))
print(id(y))
print(x is y)2719226700992
2719226700992
True
Thus, since lists are mutable, if you change the list via one variable, the effect will be seen from the other variable as well.
Remember that the changes are made on the object, and variables are just like windows to look inside the object. What we see from the window x
is the same as that from the window y
.
# Append 99 to the list via x
x.append(99)# Confirm that changes happen on the object
# whether we use x or y
print(x)
print(y)[1, 2, 3, 99]
[1, 2, 3, 99]
Shallow copies
So how can we make a copy of a list so that we will not accidentally mess up the original list when manipulating on the copy? We can use .copy()
method.
# First, create a list
x = [1, 2, 3]# Make a copy
y = x.copy()# Confirm x and y are pointing to
# two different objects
print(id(x))
print(id(y))
print(x is y)2719226702912
2719226707520
False# Confirm thay share the same value
print(x)
print(y)
print(x == y)[1, 2, 3]
[1, 2, 3]
True# Now append 99 to y
y.append(99)# Confirm y has changed but x hasn't
print(x)
print(y)[1, 2, 3]
[1, 2, 3, 99]
Here, element of x
are all integers (immutable), so there's no problem. But be careful if x
contains some elements of a mutable type such as lists. Consider the following example.
# Create a list with 3 elements
# The last element is a list
x = [1, 2, [3, 4]]# Index (read) the last element
# And confirm it's a list
print(x[-1])
print(type(x[-1]))[3, 4]
<class 'list'># Since x[-1] is a list,
# we can also perform indexing on it
# for example, accessing the first element
x[-1][0]3# Now, make a copy of x
y = x.copy()# Confirm x and y are pointing to
# two different objects
print(id(x))
print(id(y))
print(x is y)2719226432896
2719226715968
False# Now, replace the 1st element
# of the last element of y by 99
y[-1][0] = 99# Confirm that the change is reflected
# on both x and y
print(x)
print(y)[1, 2, [99, 4]]
[1, 2, [99, 4]]# But they are still pointing to
# two different objects
print(id(x))
print(id(y))2719226432896
2719226715968
The reason is that .copy
only copies the references to the underlying objects, not the values. That's why this type of copy is call shallow copy. There are three ways to make a shallow copy.
y = x.copy()
y = x[:]
y = list(x)
Deep copies
To make sure that everything in x
and y
is completely separated, we need to perform a deep copy using copy
module.
# Import module
import copy# Initalize x
x = [1, 2, [3, 4]]# Deep copy x to y
y = copy.deepcopy(x)# Confirm x and y are pointing to
# two different objects
print(id(x))
print(id(y))
print(x is y)2719226675264
2719226432896
False# Now, replace the 1st element
# of the last element of x by 99
y[-1][0] = 99# Confirm change is made on y only
print(x)
print(y)[1, 2, [3, 4]]
[1, 2, [99, 4]]
Why don’t we just use deepcopy every time? Because deep copying a large list will take more time and space.
Navigation
Previous: Python’s list type (part 2) — List iteration and mutability
Next: Python’s list type (part 4) — Operations on lists