Skip to content

Prototype

Desing

The prototype is a design pattern that allows you to create objects that is divided into two stages:

  • creating a base object (e.g. partially completed) which is a copy of the finished object
  • setting the rest of the object's fields

This pattern can be used when, for example, we are working on a large application whose performance is a key factor and creating a prototype can improve the operation of our application.

Python copy

Assignment in Python does not copy an object, it only creates another reference to it. Copy modules can be used for copying:

  • shallow copy: copy.copy(x)
  • deep copy: copy.deepcopy(x)

The difference between the two methods is when you copy complex objects, i.e. objects that contain other objects, such as lists or class instances:

  • shallow copy constructs a new composite object and places references to objects from the original composite object
  • deep copy constructs a new compound object and recursively places copies of objects from the original compound object into it

Example

The following example shows a simple prototype implementation that uses a copy module and a shallow copy. In this case it is sufficient because the PythonCodeFile class does not contain complex objects.

import copy


class PythonCodeFile:
    def __init__(self, license_content, file_extension, code='', file_name='' ):
        self._license_content = license_content
        self._code = code
        self._file_name = file_name
        self._file_extension = file_extension

    @property
    def license_content(self):
        return self._license_content

    @license_content.setter
    def license_content(self, value):
        self._license_content = value

    @property
    def code(self):
        return self._code

    @code.setter
    def code(self, value):
        self._code = value

    @property
    def file_name(self):
        return self._file_name

    @file_name.setter
    def file_name(self, value):
        self._file_name = value

    @property
    def file_extension(self):
        return self._file_extension

    @file_extension.setter
    def file_extension(self, value):
        self._file_extension = value

    def create_clone(self):
        return copy.copy(self)

    def __str__(self):
        return f"File: {self._file_name}.{self._file_extension}, license=[{self._license_content}], code=[{self._code}]"
class PythonCodeFilesManager:
    _base_file = PythonCodeFile('SDA', 'py')

    @staticmethod
    def create_file_with_content(file_name, code):
        base_file_clone = PythonCodeFilesManager._base_file.create_clone()
        base_file_clone.file_name = file_name
        base_file_clone.code = code
        return base_file_clone

Pattern usage:

def main():
    file_1 = PythonCodeFilesManager.create_file_with_content('zen_of_python', 'import this')
    file_2 = PythonCodeFilesManager.create_file_with_content('test_file', 'test')

    print(file_1)
    print(file_2)


if __name__ == '__main__':
    main()