[英]How to use enum value in asdict function from dataclasses module
我有一個帶有枚舉類型字段template
的數據類。 使用asdict
function 時,它將我的數據類轉換為字典。 是否可以使用FoobarEnum
的value
屬性返回字符串值而不是枚舉 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.name
和Enum.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))
根據用例,您可以從str
和Enum
繼承或擁有一個僅初始化字段。
你試過這個嗎?
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.