Python's Prototype Design Pattern: Crafting Objects for Performance
Published: 2023-09-02 22:14:10

---
title: Python's Prototype Design Pattern: Crafting Objects for Performance
published: true
date: 2023-08-09 21:44:12 UTC
tags: 
canonical_url: https://psycode.hashnode.dev/pythons-prototype-design-pattern-crafting-objects-for-performance
---

In a previous article, we discussed the singleton design pattern and saw how it could be applied in practice. In this article, well be discussing the prototype design pattern, when to use it and how to use it.

The prototype design pattern lets you as a developer copy existing objects without making your code dependent on the classes in which they were instantiated from. So what does this mean? Say you had an object in your code and for some reason you wanted to create an exact copy of that object with its attributes, normally you would first create an object of the same class and then go through all the properties of the original object and copy over their values to the new object. However, it is important to note that not all objects can be copied that way because some of the objects properties (i.e. attributes and methods) may be private. Furthermore, you would have to know the objects class to create a duplicate and in a long codebase, this could become very tedious and this is where the prototype design pattern comes in.

Fundamentally, the prototype pattern is just a _clone()_ function that accepts an object as an argument and returns a clone of the object.

# Building a Prototype Design

Let us implement the prototype design in code as follows::

```
from abc import ABCMeta, abstractmethod
from copy import deepcopy

# prototype interface
class Prototype(metaclass=ABCMeta):
    @abstractmethod
    def clone(self):
        pass

# concrete prototype
class Car(Prototype):
    def __init__ (self, make, model, year) -> None:
        self.make = make
        self.model = model
        self.year = year

    def clone(self):
        return deepcopy(self)

# client
car_1 = Car('Dodge', 'Challenger SRT', 2021)
cloned_car = car_1.clone()

print(car_1)
print(cloned_car)
print(car_1 == cloned_car)

```

In the code above, we first import the necessary tools well need. We imported the **_ABCMeta_** class and **_abstractmethod_** decorator from the **_abc_** module. The ABCMeta class is used to define an abstract base class and the **_abstractmethod_** decorator is used to declare abstract methods that must be implemented by subclasses. We also imported the **_deepcopy_** function from the copy module. This function creates a deep copy of an object

#Abstract Class
This is a class that cannot be instantiated directly and is meant to be subclassed by other classes.
#Abstract Method
This is a method declared in abstract base classes but does not contain any implementation in the base class itself.

We then created a class **_Prototype_** , that serves as the interface for creating prototype objects. The **_metaclass=ABCMeta_** argument specifies that this class is an abstract class (i.e. a class that cannot be instantiated directly and is meant to be subclassed by other classes) and should be treated as such.

The **_@abstractmethod_** decorator marks the **_clone_** method as an abstract method. Abstract methods are declared in abstract base classes but do not contain any implementation in the base class itself. Subclasses inheriting from this base class are required to provide an implementation for this method

We then created another class, **_Car_** , which implements our **_Prototype_** base class. We created a constructor method that is to be initialized when objects are created from the class. We then defined the implementation of our abstract method **_clone_** , derived from the Prototype class implemented in our car class. The clone function takes the object as an argument and returns a deep copy of the object.

To test our code, we created a car object from the **_Car_** class, specifying all the needed attributes (make, model, year) and we named this object **_car\_1_**. We then created another object, **_cloned\_car_** , which is a clone of our first car, thanks to applying the clone method to our **_car\_1_** object.

Using our print statements, we can see they are not stored in the same memory address and they are not the same although one is a clone of the other as seen in the output below:

```
< __main__.Car object at 0x000000FF942AE2E0>
< __main__.Car object at 0x000000FF94327040>
False

```

# Applications of the Prototype Design

The prototype design is useful for:

- **Reducing Object Creation Overload:** If object creation is a computationally expensive task, using the prototype design pattern can be more efficient than creating objects from scratch.

- **Creating Stateful Objects:** Prototypes can be used to capture the state of an object at a certain point in time, making it useful for tasks such as creating snapshots and the redo/undo functionality.

- **Dynamically Creating Objects:** In cases where the exact class of an object isnt known until runtime, the prototype pattern can be helpful to achieve runtime object creation without knowing the specific classes in advance

With all that said, the keypoint is to understand that the prototype design pattern basically creates a clone of an existing object.

Thats it for this article folks, dont just read it but also try to understand and perhaps even use it. So till next time, as usual, dont break production.