python - 如何在 Protobuf 中序列化嵌套消息中的默认值
问题描述
正如标题所述,我有一条 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)。所以我将参数添加including_default_value_fields=True
到调用中MessageToDict()
:
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 )证实了这种行为:
include_default_value_fields:如果为 True,则将始终序列化奇异原始字段、重复字段和映射字段。如果为 False,则仅序列化非空字段。单个消息字段和 oneof 字段不受此选项影响。
那么,即使它们是嵌套消息中的默认值,我该怎么做才能获得包含所有值的 dict?
有趣的是,当我example.json
看起来像这样时:
{
"subMessage" : {
"number" : 0
}
}
我得到了预期的输出。但我不能确保example.json
将所有值都写出来,所以这不是一个选项。
解决方案
基于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}}
推荐阅读
- python - 发送 1gb 数据作为对 POST 请求的响应
- spring - 解析模板 [home] 时出错,模板可能不存在或可能无法被任何已配置的模板解析器访问
- ruby-on-rails - 向现有数据库模型添加验证
- java - 如何在 jersey 应用程序部署期间修复“Servlet.init() for servlet [ApplicationConfig] 引发异常”?
- cloud-foundry - 弹性运行时间 - Cloud Foundry
- c# - 从程序集中扫描自动映射器配置文件的干净方法
- angular - Ionic 3 在选择时显示离子项目
- php - CVS 结果显示在一列中
- r - 如何使用R提取具有相同时间的一对一匹配数据
- android - 如何使用 gdx-pay-android-googlebilling?