如何在 Python 中实例化数据类期间将字符串转换为 Enum

发布于 2025-01-20 22:02:58 字数 1211 浏览 1 评论 0原文

我有一个dataclass dummyClass带有属性虚拟,它只能采用两个值:“ foo”“ bar” >。我想为此属性使用enum类,以便在使用无效值时会引起错误:

from dataclasses import dataclass, field
from enum import Enum

class DummyAttribute(Enum):
    FOO = "foo"
    BAR = "bar"

@dataclass
class DummyClass:
    dummy: DummyAttribute

问题是我想使用字符串实例化dummyClass (不直接使用dummyAttribute类)。一种方法是使用__ post_init __方法:

@dataclass
class DummyClass:
    dummy: DummyAttribute = field(init=False)
    tmp_dummy: str
    def __post_init__(self):
        self.dummy = DummyAttribute(self.tmp_dummy)

但是,我宁愿避免添加tmp_dummy属性和__ post_init __init __init __方法。是否还有其他简洁的方法将输入字符串投射到dummyattribute枚举?


编辑: @chepner的答案帮助我找到了一种更简洁的方法:

from dataclasses import dataclass, field
from enum import Enum

class DummyAttribute(Enum):
    FOO = "foo"
    BAR = "bar"

@dataclass
class DummyClass:
    dummy: str | DummyAttribute
    def __post_init__(self):
        self.dummy = DummyAttribute(self.dummy)

如果有更好的方法,请告诉我!

I have a dataclass DummyClass with an attribute dummy that can only take two values: "foo" and "bar". I would like to use an Enum class for this attribute so that an error is raised when using an invalid value:

from dataclasses import dataclass, field
from enum import Enum

class DummyAttribute(Enum):
    FOO = "foo"
    BAR = "bar"

@dataclass
class DummyClass:
    dummy: DummyAttribute

The problem is that I would like to instantiate DummyClass using a string (not using the DummyAttribute class directly). One way to do it would be using the __post_init__ method:

@dataclass
class DummyClass:
    dummy: DummyAttribute = field(init=False)
    tmp_dummy: str
    def __post_init__(self):
        self.dummy = DummyAttribute(self.tmp_dummy)

However I would prefer to avoid adding a tmp_dummy attribute and a __post_init__ method. Is there any more concise way of casting the input string to the DummyAttribute enum?


Edit:
@chepner answer helped me find an even more concise way of doing it:

from dataclasses import dataclass, field
from enum import Enum

class DummyAttribute(Enum):
    FOO = "foo"
    BAR = "bar"

@dataclass
class DummyClass:
    dummy: str | DummyAttribute
    def __post_init__(self):
        self.dummy = DummyAttribute(self.dummy)

Please let me know if there is a better way!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

墨小墨 2025-01-27 22:02:58

我认为__ post_init __(您编辑的添加到问题中)是您的最佳选择。 DataClass不支持您想要的价值变压器。 (为此,您可能需要查看Pydantic或attrs软件包。)

from dataclasses import dataclass, InitVar
from enum import Enum

class DummyAttribute(Enum):
    FOO = "foo"
    BAR = "bar"


@dataclass
class DummyClass:
    dummy: DummyAttribute = field(init=False)
    dummyStr: InitVar[str]

    def __post_init__(self, dummyStr):
        self.dummy = DummyAttribute(dummyStr)

I think __post_init__ (as you edited added to your question) is your best alternative. dataclass doesn't support the kind of value transformer you want. (For that, you might want to look at Pydantic or the attrs package.)

from dataclasses import dataclass, InitVar
from enum import Enum

class DummyAttribute(Enum):
    FOO = "foo"
    BAR = "bar"


@dataclass
class DummyClass:
    dummy: DummyAttribute = field(init=False)
    dummyStr: InitVar[str]

    def __post_init__(self, dummyStr):
        self.dummy = DummyAttribute(dummyStr)
苏辞 2025-01-27 22:02:58

作为使用 Enum 的替代方案,如果您真正需要的是 str 类型,那么我建议只使用 str 来代替。

请注意,在这种情况下,typing.Literal 可能会有所帮助:

from dataclasses import dataclass
from typing import Literal


@dataclass
class DummyClass:
    dummy: Literal['foo', 'bar']

    def __post_init__(self):
        # TODO: assert that `self.dummy` is one of valid Literal values
        ...

然后您可以像这样创建实例,如果您传递无效的 Literal<,您的 IDE 会立刻向您发出警告。 /code> 字段的值。

obj1 = DummyClass('bar')
obj2 = DummyClass('blah')  # <-- warning! >:(

如前所述,如果您确实需要验证它是有效的Literal值之一,我建议将该逻辑添加到__post_init__方法中。

As an alternative to using an Enum, if what you really need is a str type then I would suggest just using a str instead.

Note that typing.Literal might be helpful in this case:

from dataclasses import dataclass
from typing import Literal


@dataclass
class DummyClass:
    dummy: Literal['foo', 'bar']

    def __post_init__(self):
        # TODO: assert that `self.dummy` is one of valid Literal values
        ...

Then you can create your instances like this, and right off the bat your IDE should throw warnings at you if you pass an invalid Literal value for a field.

obj1 = DummyClass('bar')
obj2 = DummyClass('blah')  # <-- warning! >:(

As mentioned, if you actually need to validate that it's one of the valid Literal values, I would suggest adding that logic to the __post_init__ method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文