如何在dataclasses模块的asdict函数中使用枚举值

2024-10-02 22:27:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个数据类,其字段template类型为Enum。当使用asdict函数时,它会将我的数据类转换为字典。是否可以使用FoobarEnum^{}属性来返回字符串值而不是枚举对象

我最初的想法是使用asdict函数的^{}参数并提供我自己的工厂,但我不知道如何做到这一点

from dataclasses import dataclass, asdict
from enum import Enum


@dataclass
class Foobar:
  name: str
  template: "FoobarEnum"


class FoobarEnum(Enum):
  FIRST = "foobar"
  SECOND = "baz"


foobar = Foobar(name="John", template=FoobarEnum.FIRST)

print(asdict(foobar))

电流输出:

{'name': 'John', 'template': <FoobarEnum.FIRST: 'foobar'>}

目标:

{'name': 'John', 'template': 'foobar'}

Tags: 数据函数namefromimporttemplateenumjohn
3条回答
from dataclasses import dataclass, asdict
from enum import Enum


class FoobarEnum(Enum):
    FIRST = "foobar"
    SECOND = "baz"


@dataclass
class Foobar:
    name: str
    template: FoobarEnum


def my_dict(data):

    return {
        field: value.value if isinstance(value, Enum) else value
        for field, value in data
    }


foobar = Foobar(name="John", template=FoobarEnum.FIRST)

data = {'name': 'John', 'template': 'foobar'}

assert asdict(foobar, dict_factory=my_dict) == data

这不能用标准库实现,除非我不知道有什么元类enum黑客Enum.nameEnum.value是内置的,不应该更改

使用数据类default_factory的方法也行不通。因为调用default_factory是为了生成数据类成员的默认值,而不是自定义对成员的访问

您可以将Enum成员或Enum.value作为数据类成员,这就是asdict()将返回的内容

如果希望将Enum成员(而不仅仅是Enum.value)保留为dataclass成员,并让函数将其转换为返回Enum.value而不是Enum成员的dictionary,正确的方法是实现自己的方法,将dataclass作为dictionary返回

from dataclasses import dataclass
from enum import Enum


class FoobarEnum(Enum):
    FIRST = "foobar"
    SECOND = "baz"


@dataclass
class Foobar:
    name: str
    template: FoobarEnum

    def as_dict(self):
        return {
            'name': self.name,
            'template': self.template.value
        }


# Testing.
print(Foobar(name="John", template=FoobarEnum.FIRST).as_dict())
# {'name': 'John', 'template': 'foobar'}

事实上你能做到asdict具有关键字参数dict_factory,允许您在此处处理数据:

from dataclasses import dataclass, asdict
from enum import Enum


@dataclass
class Foobar:
  name: str
  template: "FoobarEnum"


class FoobarEnum(Enum):
  FIRST = "foobar"
  SECOND = "baz"


def custom_asdict_factory(data):

    def convert_value(obj):
        if isinstance(obj, Enum):
            return obj.value
        return obj

    return dict((k, convert_value(v)) for k, v in data)


foobar = Foobar(name="John", template=FoobarEnum.FIRST)

print(asdict(foobar, dict_factory=custom_asdict_factory))
# {'name': 'John', 'template': 'foobar'}

相关问题 更多 >