简体   繁体   English

如何在初始化期间为冻结的数据类添加值

[英]how to add values for frozen dataclasses during initialization

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使用 init=False 我不需要在构造函数中提供它,因为无论如何都会生成它

however second class is Frozen because I cache its return since it's too big and too expensive to read everytime但是第二个 class 被冻结了,因为我缓存了它的返回,因为它太大而且每次都读取太贵

@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无论如何在init期间添加动态生成的属性而不是post_init,因为冻结的数据类是只读的

so I want to do something like所以我想做类似的事情

@dataclass(frozen=True)
class SecondClass:
    name: str
    code: str = name.lower()

I'd use a combination of the first approach with a custom creation function:我将第一种方法与自定义创建 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')

One option could be to use object.__setattr__ to bypass the fact that the dataclass is frozen:一种选择是使用object.__setattr__绕过数据类被冻结的事实:

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:另一种选择可能是添加一个帮助器 class 方法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'))

Another approach, using @property - doesn't store code in the class but exposes it as an attribute:另一种方法,使用@property - 不在 class 中存储code ,而是将其作为属性公开:

@dataclass(frozen=True)
class SecondClass:
    name: str

    @property
    def code(self):
        return self.name.lower()


print(SecondClass('Me').code)

Result:结果:

me

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM