This article explains how you can copy immutable objects in Python from one variable to another using shallow copy and deep copy approaches.
Python objects can be immutable (integers, float, bool, tuple, etc.), or mutable (lists, dictionaries, sets). Since immutable objects cannot be updated, copying them always copies their memory locations.
For mutable objects, you have three main ways of copying them: using an assignment operator, shallow copying an object or deep copying an object. You’ll study these three approaches in this tutorial.
Copying via Assignment Operator
Before we study the difference between shallow copying and deep copying Python objects, it’s important to understand how the assignment operator (=) assigns values to variables.
The assignment operator simply assigns the memory reference of an object into another instead of making new copies of the values stored by a variable. Let’s see an example.
The following script defines a list,
nums1 = [10, 20, 30, 40, 50]
nums2 = nums1
print(nums2)
print(nums1)
Output:
[10, 20, 30, 40, 50]
[10, 20, 30, 40, 50]
If you look at the memory location of both the
print(hex(id(nums1)))
print(hex(id(nums2)))
Output:
0x1560e31c7c0
0x1560e31c7c0
This means that when you update a value in any of the two list variables, the change will be reflected in the other list. For example, if you assign the value 500 to the second index of the
nums2[2] = 500
print(nums2)
print(nums1)
Output:
[10, 20, 500, 40, 50]
[10, 20, 500, 40, 50]
This is an important concept to understand and one you might not have realized.
Code More, Distract Less: Support Our Ad-Free Site
You might have noticed we removed ads from our site - we hope this enhances your learning experience. To help sustain this, please take a look at our Python Developer Kit and our comprehensive cheat sheets. Each purchase directly supports this site, ensuring we can continue to offer you quality, distraction-free tutorials.
Making a Shallow Copy with copy()
Function
If you want to copy the values of a variable, like list items, instead of their memory locations, you can make shallow copies of objects.
The copy()
function can be used to make a shallow copy in Python. However, in case of nested lists, the copy()
function only copies the top level list items. For the nested list items, the memory locations are copied. This is why this type of copy operation is called the shallow copy. Let’s show you what we mean.
Copying Flat Lists with copy()
Function
As discussed, whe shallow copying flat lists (think 1-dimensional lists) using the copy()
function, the values are copied instead of memory locations. Here’s an example where list
nums1 = [10, 20, 30, 40, 50]
nums2 = nums1.copy()
print(nums2)
print(nums1)
Output:
[10, 20, 30, 40, 50]
[10, 20, 30, 40, 50]
In this case, the
print(hex(id(nums1)))
print(hex(id(nums2)))
Output:
0x1560e31c200
0x1560e31c080
Now, if you update a list item in any of the two lists, that change will no logner be reflected in the other list.
nums2[1] = 500
print(nums2)
print(nums1)
Output:
[10, 500, 30, 40, 50]
[10, 20, 30, 40, 50]
Copying Nested Lists with Copy()
Function
If you shallow copy the lists containing nested sub-lists using the copy()
function, the top level list items will be shallow copied, but when you get to the nested list items, only their memory locations are copied.
Let’s see an example. The following script defines the copy()
function.
nums1 = [[1,2,3],[4,5,6],[7,8,9]]
nums2 = nums1.copy()
print(nums2)
print(nums1)
Output:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
If you print the memory locations of the top level lists, you’ll observe that the memory locations are different, as expected
print(hex(id(nums1)))
print(hex(id(nums2)))
Output:
0x1560e31e1c0
0x1560d306c40
As expected, if you update an item in the top-level list, the change is not reflected in the other list since the top level items values are copied.
nums2[1] = 500
print(nums2)
print(nums1)
Output:
[[1, 2, 3], 500, [7, 8, 9]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
However, for nested list items, only the memory locations of the items are copied. Therefore, if you update a nested list item in one list, the change will be reflected in the other list, as shown in the following script.
nums2[0][1] = 500
print(nums2)
print(nums1)
Output:
[[1, 500, 3], 500, [7, 8, 9]]
[[1, 500, 3], [4, 5, 6], [7, 8, 9]]
You can verify this by printing the memory locations of the corresponding nested items in the two lists. For instance, the output of the script below shows that the memory location of the item at the second index of the first nested list is the same for both the
print(hex(id(nums2[0][1])))
print(hex(id(nums1[0][1])))
Output:
0x1560ee55030
0x1560ee55030
Code More, Distract Less: Support Our Ad-Free Site
You might have noticed we removed ads from our site - we hope this enhances your learning experience. To help sustain this, please take a look at our Python Developer Kit and our comprehensive cheat sheets. Each purchase directly supports this site, ensuring we can continue to offer you quality, distraction-free tutorials.
Making a Deep Copy with deepcopy()
Function
Fortunately, there is a way to copy nested items to brand new memory locations with Python. If you want to recursively copy the values of all the top level and nested items in a Python object, like a list, you can use the deepcopy()
function.
Copying Flat Lists with deepcopy()
Function
While copying a flat list, the deepcopy()
functions behaves in the same way as the copy()
function; all the items are copied instead of their memory locations.
Here’s an example:
import copy
nums1 = [10, 20, 30, 40, 50]
nums2 = copy.deepcopy(nums1)
print(nums2)
print(nums1)
Output:
[10, 20, 30, 40, 50]
[10, 20, 30, 40, 50]
You can print the memory locations of the
print(hex(id(nums1)))
print(hex(id(nums2)))
Output:
0x1560d306c40
0x1560ee40ec0
Like the shallow copy, an update to the top level list item will not be reflected in the other list when using a deep copy.
nums2[1] = 500
print(nums2)
print(nums1)
Output:
[10, 500, 30, 40, 50]
[10, 20, 30, 40, 50]
Copying Nested Lists with deepcopy()
Function
When using a deep copy, the top level and the nested list items are recursively copied to new memory locations. The following script copies deepcopy()
function.
import copy
nums1 = [[1,2,3],[4,5,6],[7,8,9]]
nums2 = copy.deepcopy(nums1)
print(nums2)
print(nums1)
Output:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
You can see that the memory locations of the top level list items are different.
print(hex(id(nums1)))
print(hex(id(nums2)))
Output:
0x1560ee56300
0x1560ee44180
Therefore, a change in one of the top level list items is not reflected in the other list.
nums2[1] = 500
print(nums2)
print(nums1)
Output:
[[1, 2, 3], 500, [7, 8, 9]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Furthermore, the values, rather than the memory locations, of the nested items are copied. Therefore, a change in a nested list item is not reflected in the other list. Look at the following example:
nums2[0][1] = 500
print(nums2)
print(nums1)
Output:
[[1, 500, 3], 500, [7, 8, 9]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Finally, you can print the memory locations of the nested list items to see that they are indeed stored in different memory locations.
print(hex(id(nums2[0][1])))
print(hex(id(nums1[0][1])))
Output:
0x1560ee554f0
0x156080d6950
Conclusion
As you can see, there are multiple ways to copy objects in Python. The choice of the method depends on your personal objective. If you are only interested in copying memory locations, you can use the assignment operator (=). If you want to copy values instead of memory locations, the copy()
or deepcopy()
functions will be a better fit for you. Just remember that the copy()
function only copies values of the top level items whereas the deepcopy()
function copies values of the top level and all nested items.
Found this helpful? Subscribe using the form below for more Python tips like this one.
Code More, Distract Less: Support Our Ad-Free Site
You might have noticed we removed ads from our site - we hope this enhances your learning experience. To help sustain this, please take a look at our Python Developer Kit and our comprehensive cheat sheets. Each purchase directly supports this site, ensuring we can continue to offer you quality, distraction-free tutorials.