Shallow Copy and Deep Copy in Python

Shallow copy and deep copy are two concepts in Python about duplicating data structures like lists, dictionaries, or user-defined objects. They both create a new object but handle the copying of nested objects differently, such as lists inside lists.

1. Shallow Copy

A shallow copy creates a new object that is a copy of the original. However, it does not recursively copy objects that are contained within the original. Instead, it only copies references to those inner objects.

Key Characteristics

  • A new object is declared.
  • Inner (nested) objects are not copied, but only references to them are.
  • The mutable inner objects are changed both for the original and the copied object.

How to Create a Shallow Copy

1. Using the copy module:

import copy
shallow_copy = copy.copy(original_object)

2. Using slicing (for lists):

shallow_copy = original_list[:]

3. Using the list() or dict() constructor:

shallow_copy = list(original_list)
shallow_copy = dict(original_dict)

Example

import copy

original_list = [[1, 2, 3], [4, 5, 6]]
shallow_copy = copy.copy(original_list)

# Modify the inner list
shallow_copy[0][0] = 99

print("Original List:", original_list)
print("Shallow Copy:", shallow_copy)

Output:

Original List: [[99, 2, 3], [4, 5, 6]]
Shallow Copy: [[99, 2, 3], [4, 5, 6]]

Explanation:

  • The outer list is copied as a new object.
  • The inner lists are still shared references between original_list and shallow_copy.
  • Modifying the inner list affects both the original and the shallow copy.

2. Deep Copy

A deep copy produces a new object and recursively duplicates all objects within the original so that the result is a completely independent copy.

Key Characteristics

  • A new object is created.
  • Inner (nested) objects are copied as well.
  • Inner objects in the copy do not have any effects on the original and vice versa.

How to Create a Deep Copy

Using the copy module:

import copy
deep_copy = copy.deepcopy(original_object)

Example

import copy

original_list = [[1, 2, 3], [4, 5, 6]]
deep_copy = copy.deepcopy(original_list)

# Modify the inner list
deep_copy[0][0] = 99

print("Original List:", original_list)
print("Deep Copy:", deep_copy)

Output:

Original List: [[1, 2, 3], [4, 5, 6]]
Deep Copy: [[99, 2, 3], [4, 5, 6]]

Explanation:

  • Both the outer list and the inner lists are duplicated.
  • Changes made to the deep_copy do not affect the original_list, as they are completely independent objects.

Comparison: Shallow Copy vs. Deep Copy

FeatureShallow CopyDeep Copy
DefinitionCopies the object without nested objectsCopies the object and all nested objects recursively
Nested ObjectReferences are copiedEntire structure is duplicated
Memory UsageLowerHigher
Modification EffectAffects both original and copyChanges are independent

When to Use Which?

  1. Shallow Copy: Use when the inner objects of the original object will not change, or when you intentionally want the original and copied objects to share the same inner objects.
  2. Deep Copy: Use when you need a completely independent copy and want to avoid any unintended side effects caused by shared references.

Important Points

1. Immutable Objects:

  • For immutable objects (for example, integers, strings, tuples), both shallow copy and deep copy perform identically as the objects are not modifiable.

2. Performance:

  • Shallow copy is faster with less memory requirements.
  • Deep copy may be slower and more memory-intensive because of the recursive copy.

3. Cyclic References:

  • The deepcopy method handles cyclic references (when an object has a reference back to itself). The method prevents an infinite recursion during its copy operation.