如何在数据类模块的 asdict 函数中使用枚举值
How to use enum value in asdict function from dataclasses module
我有一个数据类,其字段 template
类型为 Enum。使用 asdict
函数时,它将我的数据类转换为字典。是否可以使用 FoobarEnum
的 value
属性来 return 字符串值而不是 Enum 对象?
我最初的想法是使用 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))
当前输出:
{'name': 'John', 'template': <FoobarEnum.FIRST: 'foobar'>}
目标:
{'name': 'John', 'template': 'foobar'}
这不能用标准库来完成,除非通过一些我不知道的元类枚举 hack。 Enum.name
和 Enum.value
是内置的,不应更改。
使用数据类 default_factory
的方法也行不通。因为调用 default_factory
来为数据类成员生成默认值,而不是自定义对成员的访问。
您可以将 Enum 成员或 Enum.value 作为数据类成员,这就是 asdict()
将要 return 的情况。
如果您想保留一个 Enum 成员 - 而不仅仅是 Enum.value- 作为数据类成员,并且有一个函数将其转换为 return 的 Enum.value 字典枚举成员的正确方法是实现您自己的方法 return 数据类作为字典。
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
函数处理数据类、元组、列表和字典。如果是任何其他类型,它会调用:
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))
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
其实你可以做到的。 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'}
我有一个类似的问题,我需要将我的数据 class 对象序列化为 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
的行为,但我现在可以序列化该对象。
参考:Serialising an Enum member to JSON
我有一个数据类,其字段 template
类型为 Enum。使用 asdict
函数时,它将我的数据类转换为字典。是否可以使用 FoobarEnum
的 value
属性来 return 字符串值而不是 Enum 对象?
我最初的想法是使用 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))
当前输出:
{'name': 'John', 'template': <FoobarEnum.FIRST: 'foobar'>}
目标:
{'name': 'John', 'template': 'foobar'}
这不能用标准库来完成,除非通过一些我不知道的元类枚举 hack。 Enum.name
和 Enum.value
是内置的,不应更改。
使用数据类 default_factory
的方法也行不通。因为调用 default_factory
来为数据类成员生成默认值,而不是自定义对成员的访问。
您可以将 Enum 成员或 Enum.value 作为数据类成员,这就是 asdict()
将要 return 的情况。
如果您想保留一个 Enum 成员 - 而不仅仅是 Enum.value- 作为数据类成员,并且有一个函数将其转换为 return 的 Enum.value 字典枚举成员的正确方法是实现您自己的方法 return 数据类作为字典。
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
函数处理数据类、元组、列表和字典。如果是任何其他类型,它会调用:
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))
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
其实你可以做到的。 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'}
我有一个类似的问题,我需要将我的数据 class 对象序列化为 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
的行为,但我现在可以序列化该对象。
参考:Serialising an Enum member to JSON