How to Implement the Prototype Pattern with Deep Copy in Python
Implements the Prototype design pattern using copy.deepcopy to clone complex objects without sharing mutable state.
Python code
27 linesimport copy
from dataclasses import dataclass, field
from typing import List
@dataclass
class Engine:
horsepower: int
@dataclass
class Car:
brand: str
engine: Engine
accessories: List[str] = field(default_factory=list)
def clone_prototype(car: Car) -> Car:
return copy.deepcopy(car)
if __name__ == "__main__":
original = Car("Tesla", Engine(450), ["Autopilot", "Sunroof"])
cloned = clone_prototype(original)
# Mutate the clone only
cloned.engine.horsepower = 500
cloned.accessories.append("Heated seats")
print("Original:", original)
print("Cloned :", cloned)
Output
Original: Car(brand='Tesla', engine=Engine(horsepower=450), accessories=['Autopilot', 'Sunroof'])
Cloned : Car(brand='Tesla', engine=Engine(horsepower=500), accessories=['Autopilot', 'Sunroof', 'Heated seats'])
How it works
The Prototype pattern lets you create new objects by copying an existing template rather than rebuilding from scratch. copy.deepcopy recursively duplicates all nested objects, so the cloned Engine gets its own memory space. Mutating the clone's nested attributes never leaks back to the original. Dataclasses with field(default_factory=list) give each instance a fresh mutable list, avoiding shared reference bugs.
Common mistakes
- Using `copy.copy` instead of `copy.deepcopy` — the clone shares nested mutable objects with the original.
- Adding a mutable default like `accessories=[]` directly in the dataclass, which is shared across all instances.
- Forgetting to return the deep copy when wrapping the pattern in a factory function.
Variations
- Use `copy.deepcopy(obj)` directly instead of a wrapper function when you only have one clone site.
- Implement a `clone()` method on the class that internally calls `copy.deepcopy(self)` for a more OOP-oriented interface.
Real-world use cases
- Cloning configuration objects before applying environment-specific overrides in a CI/CD system.
- Duplicating UI component state trees in a frontend data layer to support undo/redo features.
- Instantiating new parser contexts from a base context without mutating the shared template used by other workers.
Sponsored
More from System design patterns
- Build a BFF (Backend for Frontend) Mock Aggregator in Python medium
- Builder pattern for mocking complex objects in Python easy
- Circuit Breaker Pattern in Python: Closed, Open, and Half-Open States medium
- Create a Data Helper Class in Python easy
- Domain Driven Design Aggregate Root Example in Python medium
- Facade Pattern in Python with Mock Simplification medium
Keep learning
Related tutorials and quizzes for this topic.