Shallow Copy vs Deep Copy in the Prototype Pattern
Prototype Pattern Series
This article is part 2 of 4 in the current sequence.
Creates a new outer object, but nested mutable objects can still be shared with the original.
Recursively duplicates nested objects too, which usually matches what beginners expect from a true clone.
This is not about which copy function sounds better. It is about whether the clone should share nested state or not.
The Prototype Pattern becomes much easier to misuse the moment nested data enters the picture. At the surface, cloning an object sounds simple enough. Make a copy, adjust the copy, and move on. But the real question is not whether a new top-level object was created. The real question is what happened to the objects inside it.
That is where shallow copy and deep copy stop being small Python utilities and start becoming design decisions. This article is not here to explain when Prototype helps in general. It is here to explain the technical fork inside the pattern: when your copy should share nested objects, and when it absolutely should not.
Prototype Depends on Copying, So the Copying Rules Matter
The Prototype Pattern creates new objects by cloning existing ones. That already assumes something important: the copy should behave the way you expect after it is made. If the copy carries hidden references back into the original, the whole point of cloning can get blurry very quickly.
In Python, the copy module gives you two common choices: copy.copy()
and copy.deepcopy(). They sound close. Their behavior is not.
Shallow Copy Creates a New Outer Object
A shallow copy makes a new top-level object, but it does not recursively copy the objects inside it. Nested objects are still shared.
import copy
original_list = [[1, 2, 3], [4, 5, 6]]
shallow_copied_list = copy.copy(original_list)
shallow_copied_list[0][0] = 99
print(original_list)
print(shallow_copied_list)
That behavior surprises beginners because the outer list was copied, but the inner lists were not. Both top-level lists still point to the same nested objects.
Why This Matters Inside Prototype
If your prototype contains nested lists, dictionaries, or other mutable objects, a shallow copy can quietly preserve those shared references. That means the clone may not be as independent as it looks.
import copy
class Prototype:
def __init__(self):
self.data = {"items": [1, 2, 3]}
def clone(self):
return copy.copy(self)
original = Prototype()
clone = original.clone()
clone.data["items"].append(4)
print(original.data)
print(clone.data)
In that example, both objects still share the same nested list. The clone exists, but part of its state is still tied to the original.
Deep Copy Recursively Separates the Nested Data
A deep copy goes farther. It creates a new top-level object and recursively copies the nested objects inside it. That gives the clone much stronger independence.
import copy
original_list = [[1, 2, 3], [4, 5, 6]]
deep_copied_list = copy.deepcopy(original_list)
deep_copied_list[0][0] = 99
print(original_list)
print(deep_copied_list)
This time, changing the copied structure does not leak into the original.
Deep Copy Fits the Usual Prototype Expectation Better
Most beginners think “clone” means independence. Deep copy is usually the version that matches that expectation.
That is why deep copy often feels more natural in Prototype examples. If the pattern is being used to create a new object that will be customized separately, shared nested state usually works against that goal rather than helping it.
import copy
class Prototype:
def __init__(self):
self.data = {"items": [1, 2, 3]}
def clone(self):
return copy.deepcopy(self)
original = Prototype()
clone = original.clone()
clone.data["items"].append(4)
print(original.data)
print(clone.data)
Now the change stays inside the clone, which is usually what readers expect when they hear the word “prototype.”
When Shallow Copy Can Still Be Valid
Shallow copy is not wrong. It is just more specific. It makes sense when you intentionally want some nested state to remain shared between the prototype and the copy. That can be efficient, but it also demands that the sharing be deliberate.
The danger is not shallow copy itself. The danger is accidentally using shallow copy while believing you created a fully independent clone.
The Real Choice Is About Shared Nested State
That is the cleanest way to think about it. Shallow copy means the outer object changes but nested references may still be shared. Deep copy means the nested structure is duplicated too. So the real question is not “Which copy function is better?” The real question is “Should the clone share nested state with the original or not?”
What a Beginner Should Keep
In Prototype code, shallow copy creates a new outer shell while preserving references to inner objects. Deep copy creates a more independent clone by recursively copying those inner objects too. If you expect the clone to be safely customized without affecting the original, deep copy is usually the safer fit.
If you want shared nested state on purpose, shallow copy may be exactly right. But that choice should be intentional, not accidental.
Frequently Asked Questions
These are the practical questions beginners usually have when shallow copy and deep copy start affecting Prototype behavior.
What is the main difference between shallow copy and deep copy?
Shallow copy creates a new outer object but can still share nested objects with the original. Deep copy duplicates the nested structure too.
Why does this matter so much in the Prototype Pattern?
Because Prototype depends on cloning. If nested state stays shared by accident, the clone may not behave like an independent new object.
Why does shallow copy surprise beginners?
Because the outer object really is new, which makes it look independent at first, even though the nested mutable objects may still be shared.
Does deep copy always mean “better”?
Not always. Deep copy is usually the safer fit when the clone should be independent, but shallow copy can be correct when shared nested state is intentional.
What is the real design question here?
The real question is whether the clone should share nested state with the original or not.
Why does deep copy often feel more natural in Prototype examples?
Because most readers hear “clone” and assume the result can be changed freely without affecting the original. Deep copy usually matches that expectation better.
When is shallow copy actually useful?
It is useful when shared nested objects are part of the design, often for efficiency or deliberate shared configuration, rather than an accident.
What is the safest beginner rule?
If the clone is supposed to be independently customizable, start by assuming deep copy is the safer choice unless you have a clear reason to share nested state.
Comments