【问题标题】:How to serialize default values in nested messages in Protobuf如何在 Protobuf 中序列化嵌套消息中的默认值
【发布时间】:2019-07-25 13:40:08
【问题描述】:

正如标题所述,我有一条 protobuf 消息,其中包含另一条消息,如下所示:

syntax = "proto3";

message Message
{
    message SubMessage {
        int32 number = 1;
    }
    
    SubMessage subMessage = 1;
}

我的example.json 是空的(这意味着到处都是默认值):

{
}

在我的 python 脚本中,我阅读了这条消息:

example_json = open("example.json", "r").read()

example_message = example.Message()
google.protobuf.json_format.Parse(example_json, example_message)

当我检查example_message.subMessage.number 的值时,它是正确的0

现在我想将其转换为存在 所有 值的字典 - 甚至是默认值。 对于转换,我使用方法google.protobuf.json_format.MessageToDict()。 但是您可能知道MessageToDict() 不会在没有我告诉它的情况下序列化默认值(例如在这个问题中:Protobuf doesn't serialize default values)。 所以我在MessageToDict()的调用中添加了参数including_default_value_fields=True

protobuf.MessageToDict(example_message, including_default_value_fields=True)

返回:

{}

而不是我的预期:

{'subMessage': {'number': 0}}

protobuf 代码中的注释(可在此处找到:https://github.com/protocolbuffers/protobuf/blob/master/python/google/protobuf/json_format.py)证实了这种行为:

包括_default_value_fields:如果为真,奇异原始字段, 重复字段,并且映射字段将始终被序列化。如果 假,只序列化非空字段。单个消息字段 并且 oneof 字段不受此选项影响。

那么,即使它们是嵌套消息中的默认值,我该怎么做才能获得具有 all 值的 dict?


有趣的是,我的example.json 看起来像这样:

{
    "subMessage" : {
        "number" : 0
    }
}

我得到了预期的输出。 但我无法确保 example.json 会写出所有值,所以这不是一个选项。

【问题讨论】:

    标签: python json dictionary protocol-buffers protobuf-3


    【解决方案1】:

    根据Looping over Protocol Buffers attributes in Python 的回答,我创建了一个自定义的MessageToDict 函数:

    def MessageToDict(message):
        message_dict = {}
        
        for descriptor in message.DESCRIPTOR.fields:
            key = descriptor.name
            value = getattr(message, descriptor.name)
            
            if descriptor.label == descriptor.LABEL_REPEATED:
                message_list = []
                
                for sub_message in value:
                    if descriptor.type == descriptor.TYPE_MESSAGE:
                        message_list.append(MessageToDict(sub_message))
                    else:
                        message_list.append(sub_message)
                
                message_dict[key] = message_list
            else:
                if descriptor.type == descriptor.TYPE_MESSAGE:
                    message_dict[key] = MessageToDict(value)
                else:
                    message_dict[key] = value
        
        return message_dict
    

    鉴于从空 example.json 读取的消息,此函数返回:

    {'subMessage': {'number': 0}}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-19
      • 2019-07-07
      相关资源
      最近更新 更多