在Python中访问Protobuf消息的未知类型的字段
问题内容:
假设我有2个Protobuf消息,A和B。它们的总体结构相似,但不完全相同。因此,我们将共享的内容移到了一条称为“普通”的单独消息中。这很漂亮。
但是,我现在面临以下问题:存在一个特殊情况,我必须处理序列化消息,但是我不知道它是A型消息还是B型消息。我在C
++中有一个可行的解决方案(如图下方),但是我没有找到在Python中执行相同操作的方法。
例:
// file: Common.proto
// contains some kind of shared struct that is used by all messages:
message Common {
...
}
// file: A.proto
import "Common.proto";
message A {
required int32 FormatVersion = 1;
optional bool SomeFlag [default = true] = 2;
optional Common CommonSettings = 3;
... A-specific Fields ...
}
// file: B.proto
import "Common.proto";
message B {
required int32 FormatVersion = 1;
optional bool SomeFlag [default = true] = 2;
optional Common CommonSettings = 3;
... B-specific Fields ...
}
C ++中的工作解决方案
在C ++中,我使用反射API来访问CommonSettings字段,如下所示:
namespace gp = google::protobuf;
...
Common* getCommonBlock(gp::Message* paMessage)
{
gp::Message* paMessage = new gp::Message();
gp::FieldDescriptor* paFieldDescriptor = paMessage->GetDescriptor()->FindFieldByNumber(3);
gp::Reflection* paReflection = paMessage->GetReflection();
return dynamic_cast<Common&>(paReflection->GetMessage(*paMessage,paFieldDescriptor));
}
方法“ getCommonBlock ”使用 FindFieldByNumber()
来获取我要获取的字段的描述符。然后,它使用反射来获取实际数据。只要Common字段保持在索引3处, getCommonBlock
可以处理类型为A,B或任何将来类型的消息。
我的问题是:有没有办法做类似的事情Python?我一直在看Protobuf文档,但找不到解决方法。
问题答案:
我知道这是一个旧线程,但是无论如何我都会回应后代:
首先,如您所知,不可能仅从其序列化形式确定协议缓冲区消息的类型。您可以访问序列化形式中的唯一信息是字段号及其序列化值。
其次,做到这一点的“正确”方法是拥有一个包含两者的原型,例如
message Parent {
required int32 FormatVersion = 1;
optional bool SomeFlag [default = true] = 2;
optional Common CommonSettings = 3;
oneof letters_of_alphabet {
A a_specific = 4;
B b_specific = 5;
}
}
这样,就不会有歧义:Parent
每次都只需解析相同的proto()。
无论如何,如果现在更改为时已晚,我建议您执行的操作是定义仅包含共享字段的新消息,例如
message Shared {
required int32 FormatVersion = 1;
optional bool SomeFlag [default = true] = 2;
optional Common CommonSettings = 3;
}
然后,您应该可以假装该消息(A
或B
)实际上是a Shared
,并进行相应的解析。未知字段将无关紧要。