Python:如何从json解码枚举类型

yve*_*owe 1 python enums json messages

class MSG_TYPE(IntEnum):
    REQUEST = 0
    GRANT = 1
    RELEASE = 2
    FAIL = 3
    INQUIRE = 4
    YIELD = 5

    def __json__(self):
        return str(self)

class MessageEncoder(JSONEncoder):
    def default(self, obj):
        return obj.__json__()

class Message(object):
    def __init__(self, msg_type, src, dest, data):
        self.msg_type = msg_type
        self.src = src
        self.dest = dest
        self.data = data

    def __json__(self):
        return dict (\
            msg_type=self.msg_type, \
            src=self.src, \
            dest=self.dest, \
            data=self.data,\
            )

    def ToJSON(self):
        return json.dumps(self, cls=MessageEncoder)

msg = Message(msg_type=MSG_TYPE.FAIL, src=0, dest=1, data="hello world")
encoded_msg = msg.ToJSON()
decoded_msg = yaml.load(encoded_msg)
print type(decoded_msg['msg_type'])
Run Code Online (Sandbox Code Playgroud)

在调用时print type(decoded_msg['msg_type']),我得到结果<type 'str'>而不是原始MSG_TYPTE类型.我觉得我也应该写一个自定义的json解码器,但有点混淆如何做到这一点.有任何想法吗?谢谢.

aba*_*ert 6

当调用print type(decoding_msg ['msg_type'])时,我得到结果而不是原始的MSG_TYPTE类型.

嗯,是的,那是因为你告诉我MSG_TYPE这样编码:

def __json__(self):
    return str(self)
Run Code Online (Sandbox Code Playgroud)

所以,这显然会解码回字符串.如果你不想那样,想出一些独特的方法来编码值,而不是只编码它们的字符串表示.

最常见的方法是使用一些特殊形式对所有自定义类型(包括枚举类型)进行object编码,就像您所做的那样Message.例如,您可以py-typeobject其中放置一个字段来编码对象的类型,然后其他字段的含义都取决于类型.理想情况下,你需要抽象出共性,而不是将相同的东西硬编码100次,当然.


我觉得我也应该写一个自定义的json解码器,但有点混淆如何做到这一点.

那你看过文件吗?你到底在哪里感到困惑?通过对StackOverflow问题的后续跟进,你不会得到一个完整的教程......

假设您object的所有类型都有一个特殊的结构,您可以使用an object_hook将值解码回原始数据.例如,作为一个快速黑客:

class MessageEncoder(JSONEncoder):
    def default(self, obj):
        return {'py-type': type(obj).__name__, 'value': obj.__json__()}

class MessageDecoder(JSONDecoder):
    def __init__(self, hook=None, *args, **kwargs):
        if hook is None: hook = self.hook
        return super().__init__(hook, *args, **kwargs)
    def hook(self, obj):
        if isinstance(obj, dict):
            pytype = obj.get('py-type')
            if pytype:
                t = globals()[pytype]
                return t.__unjson__(**obj['value'])
        return obj
Run Code Online (Sandbox Code Playgroud)

现在,在你的Message课堂上:

@classmethod
def __unjson__(cls, msg_type, src, dest, data):
    return cls(msg_type, src, dest, data)
Run Code Online (Sandbox Code Playgroud)

你需要一个MSG_TYPE.__json__返回一个字典,也许只是{'name': str(self)},然后一个__unjson__做类似的东西getattr(cls, name).

现实生活中的解决方案可能应该让类自己注册而不是按名称查找它们,或者应该通过合格的名称来处理它们,而不是仅仅去查找它们globals().并且您可能希望将事物编码为object-or之外的其他内容,如果不是,则只需填充py-type对象而不是将其包装在另一个对象中.并且可能有其他方法可以使JSON更紧凑和/或可读.并且一点点错误处理会很好.等等.


您可能希望查看jsonpickle-not 的实现,因为您想要执行完全相同的操作,但要查看它是如何连接所有部分的.