Skip to main content
 首页 » 编程设计

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

2025年05月04日15bhlsheji

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']) 

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

请您参考如下方法:

When calling print type(decoded_msg['msg_type']), I get the result instead of the original MSG_TYPTE type.

嗯,是的,那是因为你告诉 MSG_TYPE 像这样对自己进行编码:

def __json__(self): 
    return str(self) 

所以,这显然要解码回字符串。如果您不想这样,请想出一些独特的方法来对值进行编码,而不仅仅是对它们的字符串表示形式进行编码。

最常见的方法是使用某种特殊形式的 object 对所有自定义类型(包括枚举类型)进行编码——就像您为 Message< 所做的一样。例如,您可能会在 object 中放置一个 py-type 字段,它对对象的类型进行编码,然后其他字段的含义都取决于类型。理想情况下,您当然希望抽象出共性,而不是对同一事物进行 100 次硬编码。


I feel like I should also write a custom json decoder but kind of confused how to do that.

嗯,你读过the documentation吗? ?你到底哪里糊涂了?您不会通过跟踪 StackOverflow 问题来获得完整的教程……

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

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 

现在,在您的 Message 类中:

@classmethod 
def __unjson__(cls, msg_type, src, dest, data): 
    return cls(msg_type, src, dest, data) 

你需要一个返回字典的MSG_TYPE.__json__,可能只是{'name': str(self)},然后是一个__unjson__ 执行类似于 getattr(cls, name) 的操作。

现实生活中的解决方案可能应该让类自行注册而不是通过名称查找它们,或者应该处理通过限定名称查找它们而不是仅仅转到 globals()。你可能想让事情编码成 object 以外的东西——或者,如果不是,只是将 py-type 塞进对象而不是将它包装在另一个对象中。并且可能还有其他方法可以使 JSON 更紧凑和/或可读。一点点错误处理会很好。等等。


你可能想看看 jsonpickle 的实现— 不是因为您想做与它完全相同的事情,而是想看看它如何将所有部分联系起来。