Fundamentals 10 min read

Master Python Shallow vs Deep Copy: Avoid Hidden Bugs and Boost Your Code

This article explains the difference between shallow and deep copying in Python, shows why simple copies can unintentionally modify original data, provides visual memory diagrams, demonstrates multiple copying methods with code examples, compares performance, and offers practical guidelines for choosing the right copy technique in real projects.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Master Python Shallow vs Deep Copy: Avoid Hidden Bugs and Boost Your Code

Introduction

Copying data in Python may seem straightforward, but many developers encounter surprising bugs when modifications to a copied variable affect the original. This article uncovers the pitfalls of shallow copying and shows how mastering both shallow and deep copies can become a powerful tool for memory management and interview preparation.

1. A Confusing Example

original_list = [1, 2, [3, 4]]
copied_list = original_list.copy()  # shallow copy

# modify first‑level element
copied_list[0] = 99
# modify second‑level element
copied_list[2][0] = 88

print("Original:", original_list)
print("Copied:", copied_list)

Output:

Original: [1, 2, [88, 4]]
Copied: [99, 2, [88, 4]]

The change to copied_list[2][0] also altered original_list because the inner list was shared – a classic shallow‑copy pitfall.

2. Visualizing Memory Structure

Memory diagram of shallow copy
Memory diagram of shallow copy

3. Understanding Objects in Python

Immutable Objects

Numbers (int, float)

Strings (str)

Tuples (tuple)

Booleans (bool)

These objects cannot be altered after creation; any "modification" creates a new object.

Mutable Objects

Lists (list)

Dictionaries (dict)

Sets (set)

Custom objects

These objects can be changed in place, keeping the same memory address.

4. Shallow Copy (Shallow Copy): Surface‑Level Duplication

How to Create a Shallow Copy

import copy
# Method 1: copy module
new_list = copy.copy(original_list)
# Method 2: list's copy() method
new_list = original_list.copy()
# Method 3: slicing
new_list = original_list[:]
# Method 4: constructor
new_list = list(original_list)

How Shallow Copy Works

Shallow copy mechanism
Shallow copy mechanism

Only the first level of the object is duplicated; deeper levels remain references to the original objects.

Verification Example

original = [1, 2, [3, 4]]
shallow_copied = original.copy()
# modify first level
shallow_copied[0] = 99
print("After first‑level change:", original, shallow_copied)
# modify second level
shallow_copied[2][0] = 88
print("After second‑level change:", original, shallow_copied)

Result shows the first‑level change is isolated, while the second‑level change affects the original.

5. Deep Copy (Deep Copy): Complete Separation

How to Create a Deep Copy

import copy
original = [1, 2, [3, 4]]
deep_copied = copy.deepcopy(original)

How Deep Copy Works

Deep copy mechanism
Deep copy mechanism

All nested objects are recursively duplicated, producing a fully independent copy.

Verification Example

original = [1, 2, [3, 4]]
deep_copied = copy.deepcopy(original)
# modify any level
deep_copied[0] = 99
deep_copied[2][0] = 88
print("Original:", original)
print("Deep copy:", deep_copied)

The original list remains unchanged, confirming complete independence.

6. Shallow vs Deep Copy Comparison Table

Feature

Shallow Copy

Deep Copy

Copy depth

Only first level

Recursively copies all levels

Memory usage

Less

More

Performance

Faster

Slower (especially with deep nesting)

Independence

Partial (deep layers shared)

Fully independent

Suitable scenarios

Simple data structures

Complex nested structures

7. Practical Scenarios

Scenario 1 – When Shallow Copy Is Sufficient

# Simple list without nesting
simple_list = [1, 2, 3, 4, 5]
shallow_copy = simple_list.copy()

# Shallow copy of a one‑level dict
config = {'debug': True, 'level': 'info'}
config_copy = config.copy()

Scenario 2 – When Deep Copy Is Required

import copy
nested_data = {
    'name': 'test',
    'settings': {
        'color': 'blue',
        'size': [10, 20, 30]
    }
}
independent_copy = copy.deepcopy(nested_data)
# Modify the copy without affecting the original
independent_copy['settings']['size'][0] = 100
print(nested_data['settings']['size'][0])  # still 10

Scenario 3 – Copying Custom Objects

class Node:
    def __init__(self, value, children=None):
        self.value = value
        self.children = children if children else []

node1 = Node(1, [Node(2), Node(3)])
# Shallow copy – children list is shared
shallow_node = copy.copy(node1)
shallow_node.children[0].value = 999
print(node1.children[0].value)  # 999 (affected)
# Deep copy – completely independent
deep_node = copy.deepcopy(node1)
deep_node.children[0].value = 888
print(node1.children[0].value)  # still 2 (unaffected)

8. Performance Considerations: Avoid Overusing Deep Copy

Deep copying large data structures can be costly.

import copy, time
# Create a large nested list
big_data = [[i for i in range(1000)] for _ in range(1000)]

start = time.time()
shallow_copy = copy.copy(big_data)
print(f"Shallow copy time: {time.time() - start:.4f} seconds")

start = time.time()
deep_copy = copy.deepcopy(big_data)
print(f"Deep copy time: {time.time() - start:.4f} seconds")

Typical output shows shallow copy is orders of magnitude faster.

9. Summary & Best Practices

Understand object structure : Analyze the nesting level before copying.

Choose wisely : Use shallow copy for simple structures, deep copy for complex nested data.

Mind performance : Prefer shallow copy for large datasets unless full independence is required.

Clarify requirements : Sometimes shared references are intentional.

Test your assumptions : Write small snippets to verify copy behavior.

Decision Flow

Need complete independence? → use deepcopy Only first‑level independence? → use copy or .copy() Shared reference is acceptable? → assign directly

Performancememory managementPythondeep copycopy moduleshallow copy
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.