我正在尝试编写具有以下特征的不可变数据结构。
我试图实现的API是这个
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})
我已经写了一个像这样的实现
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)
但是,我在这里遇到了问题。
a0
工作正常,但其余的都失败了。
我相信问题在于复制/更新 _occupation
无人管理的字段。
问题:
谢谢你。
铌:
为属性定义 setter 有点打破了你的不变性假设。您需要构造新的
Occupation
,然后使用它创建新的 Person
。
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 = {'title': 'junior', 'salary': 30})
a1 = a0(name = a0.name + ' Smith')
a2 = a1(occupation = {'title': 'senior'})
a3 = a2(occupation = {'salary': 50})