Understanding Deep Copy vs. Shallow Copy in Python: Key Differences and Practical Examples

Rohit RaiRohit Rai
6 min read

Difference between deep copy and shallow copy in Python

Introduction

In Python programming, the concept of copying objects is crucial, especially when dealing with mutable data types like lists and dictionaries. Understanding how copying works and the differences between deep copy and shallow copy can save you from unexpected behaviors in your code. In this article, we'll delve into the intricacies of object copying in Python, exploring both shallow and deep copies with practical examples.

Brief Overview of Copying Objects in Python

Copying objects in Python involves creating a new object that is a duplicate of an existing one. However, the extent to which the original and the copied objects are linked depends on whether a shallow copy or a deep copy is made. Shallow copies create new objects that are references to the same elements as the original, while deep copies create entirely independent objects.

Importance of Understanding Deep Copy vs. Shallow Copy

Knowing the difference between deep copy and shallow copy is vital in scenarios where mutable objects (like lists of lists or dictionaries of dictionaries) are involved. Incorrectly applying these concepts can lead to bugs that are hard to track down, as changes to one object might unintentionally affect another.

Basics of Copying Objects

Definition of Copying in Programming

Copying in programming refers to the process of creating a duplicate of an object, which can either be a shallow or deep copy. In shallow copy, the new object is a copy of the original, but it still references the same memory locations as the original object. In deep copy, all elements of the original object are recursively copied, leading to a fully independent duplicate.

Copying Lists and Dictionaries in Python

Lists and dictionaries are common data structures in Python that can contain complex nested structures. Copying these structures is not as straightforward as copying simple data types because of their mutability and the potential for nested elements.

Shallow Copy

Definition and Concept

A shallow copy creates a new object but does not create copies of objects within the original object. Instead, it copies references to those objects. This means that if the original object contains mutable objects, changes to those objects will reflect in the shallow copy as well.

How Shallow Copy Works in Python

When a shallow copy is made, the new object is a separate entity, but its contents (references to objects) point to the same memory locations as the original.

Using the `copy.copy()` Method

Python's copy module provides a copy() function that creates a shallow copy of an object. Here’s how it works:

import copy

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

print(shallow_copy)  # Output: [1, [2, 3], 4]

Examples Demonstrating Shallow Copy

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

# Modifying the nested list in the shallow copy
shallow_copy[1].append(5)

print(original_list)  # Output: [1, [2, 3, 5], 4]
print(shallow_copy)   # Output: [1, [2, 3, 5], 4]

As seen in the example, the change to the nested list in shallow_copy affects original_list as well, demonstrating that both copies share references to the same nested objects.

Visual Representation of Shallow Copy

Original List:
[ 1 | -> [ 2, 3 ] | 4 ]

Shallow Copy:
[ 1 | -> [ 2, 3 ] | 4 ]

Advantages and Limitations

  • Advantages: Shallow copies are faster and consume less memory because they do not duplicate the objects referenced within the original object.

  • Limitations: They can lead to unintended side effects when mutable objects within the original are modified.

Deep Copy

Definition and Concept

A deep copy creates a completely independent object, including copies of objects contained within the original. This means that changes to the deep copy do not affect the original object and vice versa.

How Deep Copy Works in Python

Deep copying involves recursively copying all objects found in the original object, resulting in a fully independent clone.

Using the `copy.deepcopy()` Method

The copy.deepcopy() function from Python's copy module creates a deep copy of an object.

Examples Demonstrating Deep Copy

import copy

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

print(deep_copy)  # Output: [1, [2, 3], 4]

Examples Demonstrating Deep Copy

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

# Modifying the nested list in the deep copy
deep_copy[1].append(5)

print(original_list)  # Output: [1, [2, 3], 4]
print(deep_copy)      # Output: [1, [2, 3, 5], 4]

In this example, the change to the nested list in deep_copy does not affect original_list, highlighting the independence of the two objects.

Visual Representation of Deep Copy

Original List:
[ 1 | -> [ 2, 3 ] | 4 ]

Deep Copy:
[ 1 | -> [ 2, 3 ] | 4 ]

Advantages and Limitations

  • Advantages: Deep copies are safer to use when you need to ensure that modifications to the copy do not affect the original object.

  • Limitations: Deep copies are slower and consume more memory, as they duplicate every object in the original structure.

Differences Between Shallow Copy and Deep Copy

Reference Chains and Memory Allocation

Shallow copies only duplicate references to objects, whereas deep copies duplicate the objects themselves. This difference has implications for memory allocation and object reference chains.

Mutability and Changes in Nested Objects

With shallow copies, changes to mutable nested objects in the copy will affect the original. With deep copies, each nested object is independent, so changes to the copy do not affect the original.

Computational Overhead and Performance

Shallow copies are faster and more memory-efficient but can introduce bugs due to shared references. Deep copies, while safer, are slower and consume more memory.

Practical Use Cases

When to Use Shallow Copy

Use shallow copy when:

  • The object contains immutable data types.

  • You are only modifying the top-level structure, not the nested objects.

When to Use Deep Copy

Use deep copy when:

  • The object contains mutable data types, especially nested ones.

  • You need a fully independent copy to avoid unintended side effects.

Common Scenarios and Examples

  • Shallow Copy: Cloning a list of immutable elements (e.g., integers, strings).

  • Deep Copy: Duplicating a complex data structure like a list of lists or a dictionary of dictionaries.

Conclusion

  • Shallow Copy: Creates a new object, but references to the original object’s contents are maintained.

  • Deep Copy: Creates a completely independent copy of the object, including all nested objects.

Recap of Key Points

  • Shallow Copy: Creates a new object, but references to the original object’s contents are maintained.

  • Deep Copy: Creates a completely independent copy of the object, including all nested objects.

  • Shallow Copy Advantages: Faster and consumes less memory.

  • Shallow Copy Limitations: Can lead to unintended side effects when mutable objects within the original are modified.

  • Deep Copy Advantages: Safer to use when modifications to the copy should not affect the original object.

  • Deep Copy Limitations: Slower and consumes more memory.

  • Use Cases for Shallow Copy: When the object contains immutable data types or only the top-level structure is modified.

  • Use Cases for Deep Copy: When the object contains mutable data types, especially nested ones, and a fully independent copy is needed.

Final Thoughts on Choosing Between Shallow and Deep Copy in Python

Understanding the nuances between shallow and deep copying is essential for writing robust Python code. Knowing when to use each type can help you avoid common pitfalls related to object mutability and reference handling, ensuring that your code behaves as expected.

0
Subscribe to my newsletter

Read articles from Rohit Rai directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Rohit Rai
Rohit Rai

🌟 DevOps Engineer at IBM With a solid background in both on-premise and public cloud environments, I specialize in OpenStack, AWS, and IBM Cloud. My expertise spans across infrastructure provisioning using 🛠️ Terraform, configuration management with 🔧 Ansible, and orchestration through ⚙️ Kubernetes and OpenShift. I’m skilled in scripting with 🐍 Python and 🖥️ Bash, and have deep knowledge of Linux administration. Passionate about driving efficiency through automation, I strive to optimize and scale cloud operations seamlessly. 🌐 Additionally, I have a keen interest in data science and am excited about exploring how data-driven insights can further enhance cloud solutions and operational strategies. 📊🔍