我正在使用enum34包,并设法以自定义格式存储将Enum子类化为json的对象。然而,我有一个对象实例使用了相当多的子类IntEnum,我的自定义JSONEncoder似乎没有正确地获取它。
我最后的办法是将其转换为枚举并相应地重构所有相关代码。IntEnum的优点是我可以按位操作/测试。
下面是一个示例和自定义编码器。注意,枚举是有效的,但我认为在将其传递给默认函数之前,IntEnum会被捕获。

class TimeMode(Enum):
    NTSC = 0
    PAL = 1
    Film = 2

class UiFlags(IntEnum):
    Empty = 0
    Clear = 0
    Checked = 1
    Selected = 2
    Shared = 8

class CObjectsEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, IntEnum):
            return {'__class__': o.__class__.__name__,
                    '__value__': (o.value,)}
        if isinstance(o, Enum):
            return {'__class__': o.__class__.__name__,
                    '__value__': (o.value,)}
    return json.JSONEncoder.default(self, o)

time_mode = TimeMode.NTSC
ui_flags = UiFlags.Checked
CObjectsEncoder().encode(time_mode)
CObjectsEncoder().encode(ui_flags)

结果:
'{"__class__": "TimeMode", "__value__": [0]}' # correct encoding
'UiFlags.Checked' # incorrect encoding

有没有办法让我得到同样的结果?我假设它像int一样被转换成str,我怎么能让编码器接收IntEnum呢?

最佳答案

这里的问题是isinstance(ui_flags, int)是真的,这意味着使用了整数的标准编码。永远不会调用自定义编码器,因为内置编码器“知道”如何处理整数:

>>> isinstance(UiFlags.Checked, IntEnum)
True
>>> isinstance(UiFlags.Checked, int)
True

有办法在JSONEncoder级别解决这个问题;您可以预先处理您的结构:
def map_intenum(data):
    if isinstance(data, IntEnum):
        return {'__class__': o.__class__.__name__,
                '__value__': (o.value,)}
    if isinstance(data, dict):
        return {k: map_intenum(v) for k, v in data.iteritems()}
    if isinstance(data, (list, tuple)):
        return [map_intenum(v) for v in data]
    return data

在编码为JSON之前将其应用于要编码的数据:
json.dumps(map_intenum(data), cls=CObjectsEncoder)

下一步是覆盖JSONEncoder.iterencode()并在编码之前应用转换:
class CObjectsEncoder(json.JSONEncoder):
    def iterencode(self, o, _one_shot=False):
        o = map_intenum(o)
        return super(CObjectsEncoder, self).iterencode(o, _one_shot)
    def default(self, o):
        if isinstance(o, Enum):
            return {'__class__': o.__class__.__name__,
                    '__value__': (o.value,)}
        return super(CObjectsEncoder, self).default(o)

关于python - 如何在Python中将IntEnum从enum34序列化为json?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32444933/

10-13 05:57