I have two dataclasses that I need to add dynamicly generated attribute "code: a lower case version of the name" on both of them
for the first one I did
@dataclass()
class FirstClass:
name: str
code: Optional[str] = field(init=False)
def __post_init__(self):
self.code = self.name.lower()
with init=False I don't need to provide it in the constructor, since it's gonna be generated anyway
however second class is Frozen because I cache its return since it's too big and too expensive to read everytime
@dataclass(frozen=True)
class SecondClass:
name: str
is there anyway to add dynamically generated attribute during init and not post_init because frozen dataclasses are read-only
so I want to do something like
@dataclass(frozen=True)
class SecondClass:
name: str
code: str = name.lower()
CodePudding user response:
One option could be to use object.__setattr__
to bypass the fact that the dataclass is frozen:
from dataclasses import dataclass, field
@dataclass(frozen=True)
class SecondClass:
name: str
code: 'str | None' = field(init=False)
def __post_init__(self, ):
object.__setattr__(self, 'code', self.name.lower())
print(SecondClass('Test'))
Another option could be to add a helper class method new()
which can be used to instantiate a new SecondClass
object:
from dataclasses import dataclass
@dataclass(frozen=True)
class SecondClass:
name: str
code: 'str | None'
@classmethod
def new(cls, name: str):
return cls(name, name.lower())
print(SecondClass.new('Hello'))
CodePudding user response:
Another approach, using @property
- doesn't store code
in the class but exposes it as an attribute:
@dataclass(frozen=True)
class SecondClass:
name: str
@property
def code(self):
return self.name.lower()
print(SecondClass('Me').code)
Result:
me
CodePudding user response:
I'd use a combination of the first approach with a custom creation function:
@dataclass(frozen=True)
class SecondClass:
name: str
code: Optional[str]
def create_second(name):
return SecondClass(name, name.lower())
print(create_second('Me'))
Result:
SecondClass(name='Me', code='me')