如何将字符串表示形式的枚举反序列化?

7

我想创建一个类,该类具有枚举作为属性。这个枚举应该有一个字符串表示形式,当将使用枚举属性的类的实例转储为JSON字符串时,它会显示为人类可读的值。

在下面的最小工作示例中,我以三种不同的方式创建了三个枚举。

在反序列化之后,每个属性都表明它来自一个枚举,除了具有字符串表示的枚举。它只是一个字符串。

如果无法实现这样的结构,我想知道原因。

要求

如果您想进行测试,则必须安装jsonsattrs

pip install attrs jsons

最简工作示例

这里是一个最简工作示例。

import jsons
import attr

from enum import Enum

# ----------------------------------------------------
# create enumeration with the help of a dictionary

fruits = {
    "PINEAPPLE": "PINEAPPLE",
    "APPLE": "APPLE",
    "ORANGE": "ORANGE",
    "BANANA": "BANANA",
}

Fruit = Enum("FRUITS", fruits)

# ----------------------------------------------------
# create a classical enumeration


class Nut(Enum):

    PEANUT = 1
    HAZELNUT = 2
    CASHEW = 3
    WALNUT = 4


# ----------------------------------------------------
# create enumeration with a string representation


class Vegetable(str, Enum):

    BROCCOLI = "BROCCOLI"
    CUCUMBER = "CUCUMBER"
    POTATO = "POTATO"
    ONION = "ONION"


# ----------------------------------------------------
# create a class which uses the enumerations


@attr.s(auto_attribs=True, kw_only=True)
class Order(jsons.JsonSerializable):
    fruit: Fruit
    nut: Nut
    vegetable: Vegetable


# ----------------------------------------------------
# initialize an order object, serialize and deserialize it

order = Order(fruit=Fruit.APPLE, nut=Nut.PEANUT, vegetable=Vegetable.CUCUMBER)

json_string: str = Order.dumps(order)

order_deserialised: Order = Order.loads(json_string)

orderorder_deserialised 变量的结构:

order:              Order(fruit=<FRUITS.APPLE: 'APPLE'>, nut=<Nut.PEANUT: 1>, vegetable=<Vegetable.CUCUMBER: 'CUCUMBER'>)

order_deserialised: Order(fruit=<FRUITS.APPLE: 'APPLE'>, nut=<Nut.PEANUT: 1>, vegetable='CUCUMBER')

正如您所看到的,order_deserialised将蔬菜显示为字符串而不是枚举。


你为什么要继承 str??? class Vegetable(str, Enum):?这可能会影响到 attrs/jsons 库,我怀疑某处有一个检查 isinstance(x, str),而它没有处理 str 的子类型... "使用字符串表示创建枚举" 这不是一个合理的做法。只需编写一个 __str__ 和一个 __repr__ 方法即可。继承 str 似乎是你的问题所在。你的枚举是一个字符串,这就是继承 str 的作用,因此它被视为字符串并不奇怪。 - juanpa.arrivillaga
从根本上说,“创建具有字符串表示的枚举”并不清楚,您通过继承str想要实现什么目标 - juanpa.arrivillaga
是的,你们两个都对。我在另一个堆栈溢出条目上看到了这个结构(https://dev59.com/dFMH5IYBdhLWcg3wtRnA#58608362) 我坚持使用字典方法。感谢你们的帮助 =) - unlimitedfox
或者,当然也可以继承str,因此class Vegetable(Enum):... - juanpa.arrivillaga
这个枚举是一个类的属性,将被序列化为JSON文件。我想看到的是值,而不仅仅是数字。或者还有其他选项可以实现这一点吗? - unlimitedfox
2
你说的“值而不仅仅是数字”,指的是哪一个数字?无论如何,你的库几乎肯定允许你按照任何你想要的方式控制序列化。让‘enum’类型继承‘str’与继承‘int’一样,完全违背了‘enum’的整个目的。我重新打开了这个问题,因为我认为那个重复的问题并不是很合适。 - juanpa.arrivillaga
1个回答

2
也许您已经知道了,但我会为未来的读者回答。这个问题在JSONS 1.6.1中得到了解决,如下例所示。
import enum
import jsons

class Vegetable(str, enum.Enum):
    BROCCOLI = "BROCCOLI"

print(jsons.loads(jsons.dumps(Vegetable.BROCCOLI), Vegetable))
# This will output "Vegetable.BROCCOLI" with JSONS 1.6.1 or later

派生一个类,比如class Vegetable(str, Enum)是完全可以的,与其他评论中的说法不同。在Python 3.11中添加了类似的想法,称为StrEnum


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接