Python: Three Hidden Ways to Create Potential Bugs with Mutable Data Structures (Part I)

April 20, 2021

Operating on mutable data structures can potentially create hidden bugs that are hard to detect if you are not as familiar with some of the characteristics of the data structure. Today we want to share with you the first way that we’ve learned in the past.

List: Reference vs Shallow Copy
It’s very easy to use [list]*n to duplicate your list, forgetting the concept of reference vs copy. When you use [list] * n, you are creating a reference to the same list a. And when you try to mutate one of the elements of that duplicated list, you will end up changing it throughout the duplicated list, as you are just creating n references of the same exact list. In order to not mutate throughout the duplicated list, you would have to do [a[:] for i in range(n)] to create n copies of the list that you would like to duplicate. Please see a quick example below:

#Reference
a = [‘apple’,’orange’,’grape’,’banana’]
b = [‘plum’, ‘watermelon’, ‘cucumber’]

a_reference = [a] * 3
a_reference
[[‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’]]

a_reference[0][0] = b[0]
a_reference
[[‘plum’, ‘orange’, ‘grape’, ‘banana’], [‘plum’, ‘orange’, ‘grape’, ‘banana’], [‘plum’, ‘orange’, ‘grape’, ‘banana’]]

#Shallow Copy
a = [‘apple’,’orange’,’grape’,’banana’]
b = [‘plum’, ‘watermelon’, ‘cucumber’]

a_copy = [a[:] for i in range(3)]
a_copy
[[‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’]]

a_copy[0][0] = b[0]
a_copy
[[‘plum’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’]]

However, this only worked for immutable items, as all items in list a are strings and strings are immutable. You would have to create a deep copy with copy.deepcopy() if you are dealing with list of lists, or list of mutable data structures.

List: Shallow Copy vs. Deep Copy

#Shallow Copy doesn’t work any more in this example

import copy
a = [‘apple’,’orange’,’grape’,’banana’]
b = [‘plum’, ‘watermelon’, ‘cucumber’]

#shallow copy on immutable data structure
a_copy = [a[:] for i in range(3)]
a_copy
[[‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’]]

#shallow copy on mutable data structure
a_shallow_copy = a_copy[:]
a_shallow_copy
[[‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’]]

#deep copy on mutable data structure
a_deep_copy = copy.deepcopy(a_copy)
a_deep_copy
[[‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’]]

#mutating on the list
a_copy[1] += b
a_copy
[[‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’, ‘plum’, ‘watermelon’, ‘cucumber’], [‘apple’, ‘orange’, ‘grape’, ‘banana’]]

#shallow copy gets affected because now items are lists, which are mutable
a_shallow_copy
[[‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’, ‘plum’, ‘watermelon’, ‘cucumber’], [‘apple’, ‘orange’, ‘grape’, ‘banana’]]

#deep copy doesn’t get affected
a_deep_copy
[[‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’], [‘apple’, ‘orange’, ‘grape’, ‘banana’]]

Hope you enjoy this week’s Data Hack Tuesday. Please tune in for the Part II next week!