Introduction
The copy module provides functions for copying Python objects. Understanding the difference between shallow and deep copies is crucial for avoiding subtle bugs.
Shallow Copy
import copy
original = [1, [2, 3], 4]
shallow = copy.copy(original)
shallow[1].append(5)
print(original) # [1, [2, 3, 5], 4] - modified!
print(shallow) # [1, [2, 3, 5], 4]
Deep Copy
import copy
original = [1, [2, 3], 4]
deep = copy.deepcopy(original)
deep[1].append(5)
print(original) # [1, [2, 3], 4] - unchanged!
print(deep) # [1, [2, 3, 5], 4]
Copying Custom Objects
import copy
class Node:
def __init__(self, value, children=None):
self.value = value
self.children = children or []
def __copy__(self):
return Node(self.value, self.children)
def __deepcopy__(self, memo):
return Node(self.value, copy.deepcopy(self.children, memo))
node = Node(1, [Node(2), Node(3)])
copied = copy.deepcopy(node)
When to Use Each
import copy
# Shallow copy - for immutable data or flat structures
simple_list = [1, 2, 3]
shallow = copy.copy(simple_list)
# Deep copy - for nested mutable structures
nested = {"a": [1, 2], "b": [3, 4]}
deep = copy.deepcopy(nested)
Copy Module Functions
import copy
# copy() - shallow copy
shallow = copy.copy(obj)
# deepcopy() - deep copy
deep = copy.deepcopy(obj)
# copy.copy() and copy.deepcopy() equivalent
Practice Problems
- Copy a nested dictionary correctly
- Implement copy for a class
- Handle circular references in deep copy
- Copy a linked list structure
- Create immutable copy semantics