Skip to main content

Python Shallow Copy and Deep Copy

In Python, you can copy an object using either a Shallow Copy or a Deep Copy, depending on whether you want the copy to be independent of the original or not.

The Wrong Way to Copy an Object in Python

In Python, the = operator does not create a true copy of an object. Instead, it creates a new reference to the existing object!

To better understand this problem, consider this example in which a list named old_list is created and an object reference is passed to new_list using = operator:

old_list = [[1, 2, 3], [4, 5, 6], [7, 8, 'a']]
new_list = old_list

new_list[2][2] = 9

print('Old List:', old_list)
print('ID of Old List:', id(old_list))

print('New List:', new_list)
print('ID of New List:', id(new_list))

and the output is:

Old List: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
ID of Old List: 132938583248128
New List: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
ID of New List: 132938583248128

Notice that both variables old_list and new_list share the same ID (140673303268168), indicating that they both point to the same object in memory. This means that changes made to old_list and new_list are actually being made to the same object.

Types of Copy in Python

In Python, there are two ways to create copies:

  • Shallow Copy
  • Deep Copy
note

To make these copy work, we use the copy module: it allows to do shallow and deep copy operations.

import copy
copy.copy(x) # returns shallow copy of x
copy.deepcopy(x) # returns deep copy of x

Shallow Copy

A Shallow Copy is a copy of an object that does not create a new instance of the object's nested objects, but references the same nested objects in the original.

This means that if you modify a nested object in the surface copy, the corresponding nested object in the original object will also be modified, because both the original and the copy refer to the same nested object.

For example, create a nested list, shallow copy it using copy() method and then do some changes:

import copy

old_list = [1, 2, [3, 5], 4]
new_list = copy.copy(old_list)

# Modifying the nested list in the shallow copy
new_list[2][0] = 7

# Original list is affected because the nested list is the same instance
print(old_list) # Output: [1, 2, [7, 5], 4]
print(new_list) # Output: [1, 2, [7, 5], 4]
danger

When you change any nested elements within old_list, these changes are also reflected in new_list. This happens because both lists are referencing the same memory locations for those nested elements. Essentially, you're updating the values in memory via a pointer mechanism.

However, if you add a new sublist to old_list, this addition is exclusive to old_list. It will not be seen in new_list because new_list maintains references to the original nested objects, and you're only appending a new value, not a reference to another object.

import copy

old_list = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_list = copy.copy(old_list)

old_list.append([4, 4, 4])

print(old_list) # [[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]
print(new_list) # [[1, 1, 1], [2, 2, 2], [3, 3, 3]]

Deep Copy

A Deep Copy consists of creating a new object and recursively inserting copies of the items found in the original object into it.

This process ensures that the new object is completely independent of the original one: any changes made to the deep copy will not affect the original object and vice versa.

For example, create a nested list, deep copy it using deepcopy() method and then do some changes:

import copy

old_list = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_list = copy.deepcopy(old_list)

# Modifying the nested list in the deep copy
new_list[2][0] = 0
new_list[2][1] = 0
new_list[2][2] = 0

print(old_list) # [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
print(new_list) # [[1, 1, 1], [2, 2, 2], [0, 0, 0]]
note

If you make changes to any nested objects in original object old_list, you will see no changes to the copy new_list.

Summary of the differences between Shallow Copy and Deep Copy

The main differences between a shallow copy and a deep copy in Python are:

  • Shallow Copy

    • Quickly duplicates the outer structure of the original object, but the inner objects are not copied; references to the original objects are kept instead.
    • Changes to the copied object's inner objects will affect the original object's inner objects, as they are pointing to the same memory location.
    • Generally faster than a deep copy because it does not need to duplicate the nested objects.
  • Shallow Copy:

    • Quickly duplicates the outer structure of the original object, but the inner objects are not copied; references to the original objects are kept instead.
    • Changes to the copied object's inner objects will affect the original object's inner objects, as they are pointing to the same memory location.
    • Generally faster than a deep copy because it does not need to duplicate the nested objects