Deep Copy vs Shallow Copy in Python
Deep copy vs shallow copy in Python: how copy.copy and copy.deepcopy differ, when nested objects are shared, and how to avoid aliasing bugs with examples.
Expected Interview Answer
A shallow copy creates a new outer object but reuses references to the same nested (inner) objects, while a deep copy recursively duplicates the outer object and every nested object, so the two structures share nothing.
With a shallow copy (copy.copy, list(), slicing, or dict.copy), mutating a nested object through one copy is visible through the other because both point to the same inner object. A deep copy (copy.deepcopy) walks the whole object graph, cloning each level, and handles shared or cyclic references via a memo so nothing is duplicated twice. Deep copies are safer for fully independent data but cost more time and memory; immutable nested values make the distinction irrelevant.
- Shallow copy is fast and memory-light for flat or immutable data
- Deep copy guarantees full independence of nested structures
- copy.deepcopy handles cyclic references safely via a memo dict
- Choosing correctly prevents subtle aliasing bugs
- You can customise both with __copy__ and __deepcopy__
AI Mentor Explanation
A shallow copy is like printing a new team sheet that still names the same eleven real players; scribble an injury note on one player and every sheet referencing him shows it. A deep copy is cloning each player into a separate practice squad, so a knock to a clone leaves the originals untouched.
Step-by-Step Explanation
Step 1
Start with assignment
b = a does not copy at all; both names bind to the same object, so any mutation is shared.
Step 2
Make a shallow copy
Use copy.copy(a), a[:], list(a), or a.copy(); the outer container is new but nested objects are shared references.
Step 3
Observe the aliasing
Mutating a nested list through the shallow copy is visible through the original because both point to it.
Step 4
Make a deep copy
Use copy.deepcopy(a) to recursively clone every level, producing fully independent structures.
Step 5
Handle special cases
deepcopy uses a memo to manage shared and cyclic references; customise behaviour with __copy__/__deepcopy__.
What Interviewer Expects
- A precise definition of shallow vs deep copy in terms of nested references
- Knowledge of copy.copy and copy.deepcopy
- Awareness that slicing and dict.copy are shallow
- Understanding that assignment is not a copy at all
- Recognising deepcopy handles cyclic references via a memo
Common Mistakes
- Believing list slicing or dict.copy produces a fully independent structure
- Thinking b = a makes a copy rather than a second reference
- Using deepcopy everywhere and paying needless performance costs
- Forgetting that immutable nested values make the distinction moot
- Assuming deepcopy fails on cyclic references (it does not)
Best Answer (HR Friendly)
“A shallow copy makes a new outer box but still shares the items inside, so changing an inner item affects both copies. A deep copy duplicates everything all the way down, giving you two completely independent structures that never affect each other.”
Code Example
import copy
original = [[1, 2], [3, 4]]
shallow = copy.copy(original) # or original[:] / list(original)
deep = copy.deepcopy(original)
# Mutate a nested list through the shallow copy
shallow[0].append(99)
print(original) # [[1, 2, 99], [3, 4]] -> original changed too!
print(shallow) # [[1, 2, 99], [3, 4]]
print(deep) # [[1, 2], [3, 4]] -> deep copy is independent
# Outer objects differ, but shallow shares inner objects
print(shallow is original) # False
print(shallow[0] is original[0]) # True (shared reference)
print(deep[0] is original[0]) # False (fully cloned)Follow-up Questions
- Which built-in operations create shallow copies of lists and dicts?
- How does copy.deepcopy handle cyclic references?
- When would a shallow copy be preferable to a deep copy?
- How do you customise copying with __copy__ and __deepcopy__?
- Why does copying a tuple of lists still leave the inner lists shared under a shallow copy?
MCQ Practice
1. What does a shallow copy duplicate?
A shallow copy creates a new outer container but its elements still reference the same nested objects.
2. Which call produces fully independent nested structures?
Only copy.deepcopy recursively clones every level of the object graph.
3. What does b = a do for a list a?
Assignment binds a second name to the same object; it copies nothing.
Flash Cards
Shallow copy? — New outer object, but nested objects are shared references.
Deep copy? — Recursively clones every level so nothing is shared.
Is slicing a[:] shallow or deep? — Shallow — the inner objects are still shared.
How does deepcopy avoid infinite loops? — It keeps a memo dict of already-copied objects to handle cycles and shared refs.
Does b = a copy? — No — it is just another name for the same object.