簡體   English   中英

如何在數據類模塊的 asdict function 中使用枚舉值

[英]How to use enum value in asdict function from dataclasses module

我有一個帶有枚舉類型字段template的數據類。 使用asdict function 時,它將我的數據類轉換為字典。 是否可以使用FoobarEnumvalue屬性返回字符串值而不是枚舉 object?

我最初的想法是使用 asdict function 的asdict dict_factory=dict參數並提供我自己的工廠,但我不知道該怎么做。

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))

當前output:

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

目標:

{'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'}
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

我有一個類似的問題,我需要將我的數據類 object 序列化為 JSON 並通過添加str作為第一個 class FoobarEnum 繼承自:

import json
from dataclasses import dataclass, asdict
from enum import Enum


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


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


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

print(json.dumps(asdict(foobar)))

它不會改變asdict的行為,但我現在可以序列化 object 了。

參考: 將 Enum 成員序列化為 JSON

這不能用標准庫來完成,除非我不知道一些元類枚舉黑客。 Enum.nameEnum.value是內置的,不應更改。

使用數據類default_factory的方法也不起作用。 因為調用default_factory是為了為數據類成員生成默認值,而不是自定義對成員的訪問。

您可以將 Enum 成員或 Enum.value 作為數據類成員,這就是asdict()將返回的內容。

如果您想保留一個 Enum 成員 - 而不僅僅是 Enum.value- 作為數據類成員,並讓 function 將其轉換為返回 Enum.value 而不是 Enum 成員的字典,正確的方法是實現您的自己的方法將數據類作為字典返回。

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'}

您可以實現__deepcopy__方法來實現您想要的:

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

  def __deepcopy__(self, memo):
      return self.value

asdict function 處理數據類、元組、列表和字典。 如果是任何其他類型,它會調用:

copy.deepcopy(obj)

像這樣覆蓋__deepcopy__可能不是最好的主意。

添加__post_init__如下所示。

from dataclasses import dataclass, asdict
from enum import Enum
from typing import Union


@dataclass
class Foobar:
    name:str
    template: Union["FoobarEnum", str]
    def __post_init__(self):
        self.template = self.template.value

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

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

根據用例,您可以從strEnum繼承或擁有一個僅初始化字段。

你試過這個嗎?

import json

def dumps(object):
    def default(o):
        if isinstance(o, Enum):
            # use enum value when JSON deserialize the enum
            return o.__dict__['_value_'] 
        else:
            return o.__dict__
    return json.dumps(object, default=default)

print(json.dumps(YOUR_OBJECT_CONTAINS_ENUMS, default=default))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM