I'm trying to create a class that holds some data and is "shared" in all the code. Like the strings in Python: they are shared everywhere, as they are immutable, and only one instance with a particular value exists. I want to create the class on demand, but every time I create that class with the same parameters, I want to get the same object.
I wrote the following code:
class Data:
_instances: dict[str, "Data"] = {}
def __new__(cls, data: str) -> "Data":
if data not in cls._instances:
cls._instances[data] = super().__new__(cls)
return cls._instances[data]
def __init__(self, data: str) -> None:
self._data = data
@property
def data(self) -> str:
return self._data
@data.setter
def data(self, data: str) -> None:
raise KeyError("Cannot change an immutable object")
It seems to work, but I have a feeling of not using all the tools Python gives us to handle this cases.
Is there any way to implement this with dataclass
es? Or a more pythonic code to achieve the same?
CodePudding user response:
You can define an immutable dataclass with the frozen=True
parameter. Making a dataclass frozen
automatically makes it hashable, so you can just use functools.cache
instead of implementing your own cache:
from dataclasses import dataclass
from functools import cache
@dataclass(frozen=True)
class Data:
data: str
@cache
def __new__(cls, data: str) -> "Data":
return super().__new__(cls)
x = Data("foo")
y = Data("foo")
assert id(x) == id(y)