Clarification: If I'm interpreting the question correctly, you specifically want to work with a class annotated with the stdlib dataclasses.dataclass(frozen=True). Specifically, for your case, you might have something like this:
from dataclasses import dataclass
@dataclass(frozen=True)
class HasStringField:
some_string: str
instance = HasStringField("SOME_STRING")
instance.some_string # value: "SOME_STRING"
My understanding is that you want to implement something such that the value in instance.some_string above is actually "some_string".
Answer: There is no "built-in" way to do what you want, but there are two options that come to mind: using object.__setattr__ in __post_init__ or else using an alternative decorator that provides you with a way to create a custom constructor that still calls through to the constructor created by dataclass.
Option 1: using object.__setattr__ in __post_init__
@dataclasses.dataclass(frozen=True)
class HasStringField:
some_string: str
def __post_init__(self):
object.__setattr__(self, "some_string", self.some_string.lower())
inst = HasStringField("SOME_STRING")
inst.some_string # value: "some_string"
Option 2: custom decorator
The dataclass_with_default_init decorator in an answer to a similar question provides one such decorator.
Using the dataclass_with_default_init decorator, you'd do:
# Import / implement the decorator
@dataclass_with_default_init(frozen=True)
class HasStringField:
some_string: str
def __init__(self, some_string: str):
self.__default_init__(some_string=some_string.lower())
instance = HasStringField("SOME_STRING")
instance.some_string # value: "some_string"
...and everything else about this class would remain as if you had used the dataclass decorator instead.