在Python中访问未知类型的Protobuf消息字段

djf*_*djf 10 python reflection protocol-buffers

假设我有2个Protobuf-Messages,A和B.它们的整体结构相似,但不完全相同.所以我们将共享的东西移到一个我们称为Common的单独消息中.这很好用.

但是,我现在面临以下问题:我需要处理序列化消息的特殊情况,但我不知道它是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 ...
}
Run Code Online (Sandbox Code Playgroud)

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));
}
Run Code Online (Sandbox Code Playgroud)

方法' getCommonBlock '使用FindFieldByNumber()来获取我想要获取的字段的描述符.然后它使用反射来获取实际数据.只要Common字段仍位于索引3,getCommonBlock就可以处理A,B类型或任何未来类型的消息.

我的问题是:有没有办法做类似的Python?我一直在看Protobuf文档,但无法找到一种方法.

Rob*_*tin 5

我知道这是一个旧线程,但是无论如何我都会回应后代:

首先,如您所知,不可能仅从其序列化形式确定协议缓冲区消息的类型。您可以访问序列化格式中的唯一信息是字段号及其序列化值。

其次,做到这一点的“正确”方法是拥有一个包含两者的原型,例如

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;
   }
}
Run Code Online (Sandbox Code Playgroud)

这样,就不会有歧义:Parent每次都只需解析相同的proto()。


无论如何,如果现在为时已晚,我建议您定义仅包含共享字段的新消息,例如

message Shared {
   required int32  FormatVersion             = 1;
   optional bool   SomeFlag [default = true] = 2;
   optional Common CommonSettings            = 3;
}
Run Code Online (Sandbox Code Playgroud)

然后,您应该可以假装该消息(AB)实际上是a Shared,并相应地对其进行解析。未知字段将无关紧要。