Shallow v. Deep Copies
One of the more curcuitous topics in a beginning programming language course is that of shallow v. deep copies. It really is not difficult but it does require a little time, thinking, and practice with the concepts. The time we devoted to understanding the variable memory management model of Python in previous chapters will help us comprehend the shallow and deep copy concepts.
Three Copy Types
- Shallow Copy (.copy())- Values for top-level items are copied. Addresses of lower-level items are copied.
- Deep Copy (deepcopy()) - Values for all items are copied.
- Assignment Copy (=) - Addresses for all items are copied.
From the Python library, "The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances)." A list (compound object) is used in the examples below to illustrate the differences. The second element of the list is another list (object).
With a shallow copy, only 'top-level' values of the source list are copied into the destination list. See the lines of code below. The top-level objects in source_list are '1st_item' and '3rd_item'. The 2nd-level item in source_list is actually another list "['inner_1', 'inner_2']". With a shallow copy, the values of the '1st_item' and '3rd_item' objects are copied but the address of the embedded list is copied. Repeat the previous sentence to yourself a few times and you will have it.
The result is, after the copy, if top_level objects are changed in either the source or destination list, the other list will not be changed. However, if an element of the embedded list is changed in either the source list or the destination list, the embedded list in the other list will also change. This happens because the embedded list addresses are the same.
There is one more thing to consider. If either of the lists (source or destination) changes the embedded list itself (and not just an element within the embedded list) then a new object is created for that embedded list. So, what do you think will happen? Since an entirely new object was created for one of the embedded lists, they no longer share the common address of the original object in the list.
You can probably anticipate the behavior of deep copy operation after understanding shallow copy. The deep copy copies all values and NOT the addresses. After a deep copy, there is no association between the source and destination lists. Therefore, if either of the top-level list or the embedded lists are changed in the source, the change will have no effect on the other list (or the embedded lists) in the destination.
By the way, deepcopy() is not part of the 'core language'. Therefore, before we can use it, we must include the function from the library file which is accomplished on line 75:
from copy import deepcopy
Understanding of the shallow and deep copy concepts will come with study and practice.
For completeness, there is a section of the code example that covers the use of the assignment statement. We have seen in previous examples that when assigning one object to another the address that the source object contains is copied into the contents of the destination object such that both objects now point to the same address. The assignment copy can be seen as the opposite of the deep copy. Deep copy copies only values and assignment copy copies only addresses.
Study and recode the example below. See the comments for more explanations of the operations.
Here's the output.
If, after coding the example and extensively studying the content, the shallow/deep topic is still confusing for you, it may be helpful to review the material at shallow v. deep copies for an alternative view of the topic.