如何序列化 Protobuf 中嵌套消息中的默认值
How to serialize default values in nested messages in 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()
不会在我没有告诉它这样做的情况下序列化默认值(就像在这个问题中:)。
所以我在 MessageToDict()
:
的调用中添加了参数 including_default_value_fields=True
protobuf.MessageToDict(example_message, including_default_value_fields=True)
哪个returns:
{}
而不是我的预期:
{'subMessage': {'number': 0}}
protobuf 代码中的注释(在此处找到:https://github.com/protocolbuffers/protobuf/blob/master/python/google/protobuf/json_format.py)证实了此行为:
including_default_value_fields: If True, singular primitive fields,
repeated fields, and map fields will always be serialized. If
False, only serialize non-empty fields. Singular message fields
and oneof fields are not affected by this option.
那么,即使它们是嵌套消息中的默认值,我该怎么做才能获得具有 所有 值的字典?
有趣的是,当我的 example.json
看起来像这样时:
{
"subMessage" : {
"number" : 0
}
}
我得到了预期的输出。
但我无法确保 example.json
会写出所有值,因此这不是一个选项。
根据 的回答,我创建了一个自定义 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
这个函数returns:
{'subMessage': {'number': 0}}
如标题所述,我有一条 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()
不会在我没有告诉它这样做的情况下序列化默认值(就像在这个问题中:MessageToDict()
:
including_default_value_fields=True
protobuf.MessageToDict(example_message, including_default_value_fields=True)
哪个returns:
{}
而不是我的预期:
{'subMessage': {'number': 0}}
protobuf 代码中的注释(在此处找到:https://github.com/protocolbuffers/protobuf/blob/master/python/google/protobuf/json_format.py)证实了此行为:
including_default_value_fields: If True, singular primitive fields, repeated fields, and map fields will always be serialized. If False, only serialize non-empty fields. Singular message fields and oneof fields are not affected by this option.
那么,即使它们是嵌套消息中的默认值,我该怎么做才能获得具有 所有 值的字典?
有趣的是,当我的 example.json
看起来像这样时:
{
"subMessage" : {
"number" : 0
}
}
我得到了预期的输出。
但我无法确保 example.json
会写出所有值,因此这不是一个选项。
根据 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
这个函数returns:
{'subMessage': {'number': 0}}