Fundamentals 8 min read

Understanding Shallow Copy and Deep Copy in Python with Examples

This article explains the concepts of shallow copy and deep copy in Python, describes their differences, and provides numerous code examples—including lists, dictionaries, and custom classes—to demonstrate how to use the copy module’s copy and deepcopy functions effectively.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Understanding Shallow Copy and Deep Copy in Python with Examples

When you need to duplicate an object, copying its reference is often insufficient; you must create an independent copy. This is where shallow copy and deep copy become essential.

Shallow Copy creates a new object and fills it with references to the original object's elements; immutable types are effectively duplicated, while mutable types retain references.

Deep Copy creates a new object and recursively copies all objects found within the original, producing a fully independent clone.

Example Code

First, import the copy module, which provides the copy and deepcopy functions.

1. Shallow copy of a list

import copy
original_list = [1, 2, [3, 4]]
shallow_copied_list = copy.copy(original_list)
original_list.append(5)
original_list[2].append(6)
print("Original List:", original_list)  # Output: [1, 2, [3, 4, 6], 5]
print("Shallow Copied List:", shallow_copied_list)  # Output: [1, 2, [3, 4, 6]]

2. Deep copy of a list

import copy
original_list = [1, 2, [3, 4]]
deep_copied_list = copy.deepcopy(original_list)
original_list.append(5)
original_list[2].append(6)
print("Original List:", original_list)  # Output: [1, 2, [3, 4, 6], 5]
print("Deep Copied List:", deep_copied_list)  # Output: [1, 2, [3, 4]]

3. Shallow copy of a dictionary

import copy
original_dict = {'a': 1, 'b': 2, 'c': [3, 4]}
shallow_copied_dict = copy.copy(original_dict)
original_dict['c'].append(5)
print("Original Dict:", original_dict)  # Output: {'a': 1, 'b': 2, 'c': [3, 4, 5]}
print("Shallow Copied Dict:", shallow_copied_dict)  # Output: {'a': 1, 'b': 2, 'c': [3, 4, 5]}

4. Deep copy of a dictionary

import copy
original_dict = {'a': 1, 'b': 2, 'c': [3, 4]}
deep_copied_dict = copy.deepcopy(original_dict)
original_dict['c'].append(5)
print("Original Dict:", original_dict)  # Output: {'a': 1, 'b': 2, 'c': [3, 4, 5]}
print("Deep Copied Dict:", deep_copied_dict)  # Output: {'a': 1, 'b': 2, 'c': [3, 4]}

5. Shallow copy of a custom class

import copy
class MyClass:
def __init__(self, value):
self.value = value
original_obj = MyClass([1, 2, 3])
shallow_copied_obj = copy.copy(original_obj)
original_obj.value.append(4)
print("Original Value:", original_obj.value)  # Output: [1, 2, 3, 4]
print("Shallow Copied Value:", shallow_copied_obj.value)  # Output: [1, 2, 3, 4]

6. Deep copy of a custom class

import copy
class MyClass:
def __init__(self, value):
self.value = value
original_obj = MyClass([1, 2, 3])
deep_copied_obj = copy.deepcopy(original_obj)
original_obj.value.append(4)
print("Original Value:", original_obj.value)  # Output: [1, 2, 3, 4]
print("Deep Copied Value:", deep_copied_obj.value)  # Output: [1, 2, 3]

7. Defining a custom __copy__ method

import copy
class MyClass:
def __init__(self, value):
self.value = value
def __copy__(self):
return MyClass(self.value[:])
original_obj = MyClass([1, 2, 3])
shallow_copied_obj = copy.copy(original_obj)
original_obj.value.append(4)
print("Original Value:", original_obj.value)  # Output: [1, 2, 3, 4]
print("Shallow Copied Value:", shallow_copied_obj.value)  # Output: [1, 2, 3]

8. Defining a custom __deepcopy__ method

import copy
class MyClass:
def __init__(self, value):
self.value = value
def __deepcopy__(self, memo):
return MyClass(copy.deepcopy(self.value, memo))
original_obj = MyClass([1, 2, 3])
deep_copied_obj = copy.deepcopy(original_obj)
original_obj.value.append(4)
print("Original Value:", original_obj.value)  # Output: [1, 2, 3, 4]
print("Deep Copied Value:", deep_copied_obj.value)  # Output: [1, 2, 3]

9. Shallow copy of a complex structure

import copy
original_complex = [1, 2, [3, 4], {'a': 5, 'b': [6, 7]}]
shallow_copied_complex = copy.copy(original_complex)
original_complex[2].append(8)
original_complex[3]['b'].append(9)
print("Original Complex:", original_complex)  # Output: [1, 2, [3, 4, 8], {'a': 5, 'b': [6, 7, 9]}]
print("Shallow Copied Complex:", shallow_copied_complex)  # Output: [1, 2, [3, 4, 8], {'a': 5, 'b': [6, 7, 9]}]

10. Deep copy of a complex structure

import copy
original_complex = [1, 2, [3, 4], {'a': 5, 'b': [6, 7]}]
deep_copied_complex = copy.deepcopy(original_complex)
original_complex[2].append(8)
original_complex[3]['b'].append(9)
print("Original Complex:", original_complex)  # Output: [1, 2, [3, 4, 8], {'a': 5, 'b': [6, 7, 9]}]
print("Deep Copied Complex:", deep_copied_complex)  # Output: [1, 2, [3, 4], {'a': 5, 'b': [6, 7]}]

These examples demonstrate that a shallow copy only duplicates the top‑level structure, while a deep copy recursively clones all nested objects, ensuring complete independence between the original and the copy.

code examplesdeep copycopy moduleObject Cloningshallow copy
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login 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.