I am trying to write an immutable datastructure with the following charicteristics.
The API im trying to implement is this
a0 = Person(name = 'Jhon', occupation = {'title': 'junear', 'sallary': 30})
a1 = a(name = a0.name + ' Smith')
a2 = a1(occupation = {'title': 'seanear'})
a3 = a2(occupation = {'sallary': 50})
I have writen an implementation like so
from dataclasses import dataclass, replace, field
@dataclass(frozen=True)
class Occupation:
__call__ = replace
title: str
sallary: int
@dataclass(frozen=True)
class Person:
__call__ = replace
name: str
occupation: Occupation
@property
def occupation(self):
return self._occupation
@occupation.setter
def occupation(self, value):
if '_occupation' not in self.__dict__:
print('initalising occupation')
occ = Occupation
else:
print('updating occupation')
occ = self.occupation
if isinstance(value, tuple):
object.__setattr__(self,'_occupation', occ(*value))
elif isinstance(value, dict):
object.__setattr__(self,'_occupation', occ(**value))
elif isinstance(value, Occupation):
object.__setattr(self,'_occupation', value)
However, Im having problems here. a0
works fine, but the rest fail.
I belive the issue is with copying over/ updating the _occupation
unmannaged field.
Questions:
Thank you.
Nb:
Defining setter for a property kinda breaks your immutability assumption. You need to construct new Occupation
, and then create new Person
using it.
from dataclasses import dataclass, replace
@dataclass(frozen=True)
class Occupation:
__call__ = replace
title: str
salary: int
@dataclass(frozen=True)
class Person:
name: str
occupation: Occupation
def __call__(self, **kwargs):
try:
occupation = kwargs['occupation']
if isinstance(occupation, tuple):
occ = self.occupation(*occupation)
elif isinstance(occupation, dict):
occ = self.occupation(**occupation)
elif isinstance(occupation, Occupation):
occ = occupation
kwargs['occupation'] = occ
except KeyError:
pass
return replace(self, **kwargs)
a0 = Person(name = 'John', occupation = Occupation(title= 'junior', salary= 30))
a1 = a0(name = a0.name + ' Smith')
a2 = a1(occupation = {'title': 'senior'})
a3 = a2(occupation = {'salary': 50})