from __future__ import annotations import copy from dataclasses import dataclass from typing import Any, List class SelfReferencingEntity: def __init__(self): self.parent = None def set_parent(self, parent): self.parent = parent @dataclass class SomeComponent: """ Python provides its own interface of Prototype via `copy.copy` and `copy.deepcopy` functions. And any class that wants to implement custom implementations have to override `__copy__` and `__deepcopy__` member functions. """ some_int: int some_list_of_objects: List some_circular_ref: Any def __copy__(self) -> SomeComponent: """ Create a shallow copy. This method will be called whenever someone calls `copy.copy` with this object and the returned value is returned as the new shallow copy. """ # First, let's create copies of the nested objects. some_list_of_objects = copy.copy(self.some_list_of_objects) some_circular_ref = copy.copy(self.some_circular_ref) # Then, let's clone the object itself, using the prepared clones of the # nested objects. new = self.__class__(self.some_int, some_list_of_objects, some_circular_ref) new.__dict__.update(self.__dict__) return new def __deepcopy__(self, memo={}) -> SomeComponent: """ Create a deep copy. This method will be called whenever someone calls `copy.deepcopy` with this object and the returned value is returned as the new deep copy. What is the use of the argument `memo`? Memo is the dictionary that is used by the `deepcopy` library to prevent infinite recursive copies in instances of circular references. Pass it to all the `deepcopy` calls you make in the `__deepcopy__` implementation to prevent infinite recursions. """ # First, let's create copies of the nested objects. some_list_of_objects = copy.deepcopy(self.some_list_of_objects, memo) some_circular_ref = copy.deepcopy(self.some_circular_ref, memo) # Then, let's clone the object itself, using the prepared clones of the # nested objects. new = self.__class__(self.some_int, some_list_of_objects, some_circular_ref) new.__dict__ = copy.deepcopy(self.__dict__, memo) return new