In a previous article, we delved into the topic of memory references in Python. It is highly recommended that you revisit that article before proceeding with this one, as a solid grasp of memory references will greatly enhance your understanding of the concepts we're about to explore.
Shallow Copy
To illustrate the concept of a shallow copy, let's examine the following example:
lst = [1, [1, 2], 3]
copied = lst.copy()
copied[1].append('a')
print(lst) # Output: [1, [1, 2, 'a'], 3]
print(copied) # Output: [1, [1, 2, 'a'], 3]
In the above example, we've defined a list, lst
, which contains an integer, an inner list, and another integer.
Next, we use the copy()
method of the list to create a copy of it, storing it in a new variable called copied
.
We proceed to add a new element, 'a', to the inner list within the copied
variable.
Surprisingly, when we print both lists, we notice that the change made to the inner list of copied
has also been reflected in lst
.
Why did this happen? The reason is relatively straightforward. When we copied a list into another list, it actually generated a shallow copy of the list. In our original list, for the inner list, instead of duplicating the values, Python copied a reference to the list itself. Consequently, when it was copied into another list, the same reference was essentially duplicated. As a result, any changes made to the inner list in one variable were also manifested in the other, since both variables were referencing the same memory address.
Understanding this concept of shallow copy is paramount when dealing with intricate data structures in Python, as it can lead to unexpected outcomes if not considered carefully.
Deep Copy
To address the issue described above and create a deeper copy, where not only the top-level object but all nested objects are duplicated independently, you can use the deepcopy
method from the copy
module:
import copy
lst = [1, [1, 2], 3]
copied = copy.deepcopy(lst)
copied[1].append('a')
print(lst) # Output: [1, [1, 2], 3]
print(copied) # Output: [1, [1, 2, 'a'], 3]
In this example, instead of using the copy
method of the list, we employ the deepcopy
function from the copy
module. Now, we obtain the expected output: changes to the copied
object does not affect the original lst
.
Deep copying is particularly valuable when dealing with intricate data structures or objects that possess nested structures. It ensures that changes made to one copy do not inadvertently impact other copies by ensuring complete independence of nested objects.