Python tutorials
> Data Structures
> Lists
> What is shallow vs deep copy?
What is shallow vs deep copy?
Understanding the difference between shallow and deep copies in Python is crucial when working with mutable data structures like lists and dictionaries. A shallow copy creates a new object, but it doesn't create copies of the objects contained within the original object. Instead, it creates references to the inner objects. A deep copy, on the other hand, creates a new object and recursively creates copies of all the objects contained within the original object. This ensures that the new object is completely independent of the original.
Shallow Copy: Basics
This example demonstrates the behavior of a shallow copy. The `copy.copy()` function creates a shallow copy of `original_list`. When we modify the inner list (at index 2) in the `shallow_copy`, the corresponding inner list in the `original_list` is also modified. This is because both lists share a reference to the same inner list object.
import copy
original_list = [1, 2, [3, 4]]
shallow_copy = copy.copy(original_list)
print(f"Original list: {original_list}")
print(f"Shallow copy: {shallow_copy}")
# Modifying the inner list in the shallow copy
shallow_copy[2][0] = 5
print(f"Original list after modification: {original_list}")
print(f"Shallow copy after modification: {shallow_copy}")
Deep Copy: Basics
This example demonstrates the behavior of a deep copy. The `copy.deepcopy()` function creates a deep copy of `original_list`. When we modify the inner list (at index 2) in the `deep_copy`, the `original_list` remains unchanged. This is because the `deep_copy` contains its own independent copy of the inner list.
import copy
original_list = [1, 2, [3, 4]]
deep_copy = copy.deepcopy(original_list)
print(f"Original list: {original_list}")
print(f"Deep copy: {deep_copy}")
# Modifying the inner list in the deep copy
deep_copy[2][0] = 5
print(f"Original list after modification: {original_list}")
print(f"Deep copy after modification: {deep_copy")
Concepts Behind the Snippet
Shallow Copy: A shallow copy creates a new object (e.g., a new list), but the elements within the new object are references to the original object's elements. Changes to these inner elements will affect both the original and the shallow copy.
Deep Copy: A deep copy creates a new object and recursively copies all objects found within the original object. This means that all elements within the new object are independent copies of the original object's elements. Changes to these inner elements will only affect the deep copy. It can be more resource-intensive than a shallow copy, as it requires creating new objects for all nested elements.
Real-Life Use Case
Imagine you are building a game where players can customize their characters with different items. If you use a shallow copy to store the character's equipment, modifying an item in one character's inventory might inadvertently affect another character's inventory if they were both using the same original item object. A deep copy would prevent this, ensuring that each character has their own independent set of items. Another case is managing configuration settings where you need to modify a copy without affecting the original configuration.
Best Practices
Use a shallow copy when you only need to create a new container but don't need to modify the contents of the inner objects.
Use a deep copy when you need to ensure that the new object is completely independent of the original object, especially when dealing with nested mutable objects.
Be mindful of the performance implications of deep copying, especially for large or complex data structures. It can be significantly slower than shallow copying.
Interview Tip
When asked about shallow vs. deep copy, be prepared to explain the difference in terms of object references and independence. Provide a clear example of when each type of copy would be appropriate. Mention the performance implications of deep copying.
When to Use Them
Use Shallow Copy When:
You only need a new container.
The contained objects are immutable (e.g., numbers, strings, tuples).
You want to save memory and time.
Use Deep Copy When:
You need a completely independent copy of the data.
The contained objects are mutable (e.g., lists, dictionaries).
You need to modify the copy without affecting the original.
Memory Footprint
Shallow copies generally have a smaller memory footprint because they only create a new container and store references to the original objects. Deep copies, on the other hand, can have a significantly larger memory footprint, especially for deeply nested structures, as they create completely new copies of all the objects.
Alternatives
For simple cases involving only one level of nesting, you might be able to achieve a similar effect to a deep copy using list comprehensions or other methods. However, these approaches can become complex and error-prone for more deeply nested structures. The `copy.deepcopy()` function is generally the most reliable and straightforward way to create a deep copy.
For example, copying a simple list of numbers can be done efficiently via slicing: `new_list = original_list[:]`.
Pros of Shallow Copy
Faster execution time compared to deep copy.
Lower memory footprint compared to deep copy.
Suitable when you only need a new container or when the contained objects are immutable.
Cons of Shallow Copy
Modifying the contents of the copy can affect the original object, leading to unexpected behavior.
Not suitable for deeply nested mutable objects.
Pros of Deep Copy
Creates a completely independent copy of the data.
Modifying the contents of the copy does not affect the original object.
Suitable for deeply nested mutable objects.
Cons of Deep Copy
Slower execution time compared to shallow copy.
Higher memory footprint compared to shallow copy.
Can be unnecessary if you only need a new container or when the contained objects are immutable.
Why does modifying the shallow copy change the original list's inner list?
Because the shallow copy only creates references to the inner list objects in the original list. Both lists point to the same inner list in memory.
When is a deep copy absolutely necessary?
When you have nested mutable objects and you need to modify the copy without affecting the original. Think of scenarios where you want to perform operations on data without any side effects on the original source.
Is deep copy always slower than shallow copy?
Yes, deep copy is generally slower because it needs to recursively copy all nested objects, while a shallow copy only copies the top-level container.