Python中未知类型Protobuf消息的访问字段 [英] Accessing field of Protobuf message of unknown type in Python

查看:77
本文介绍了Python中未知类型Protobuf消息的访问字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let's say I have 2 Protobuf-Messages, A and B. Their overall structure is similar, but not identical. So we moved the shared stuff out into a separate message we called Common. This works beautifully.

但是,我现在面临以下问题:存在一种特殊情况,我必须处理序列化消息,但我不知道它是类型 A 还是类型 B 的消息.我有一个有效的解决方案C++(如下所示),但我没能找到在 Python 中做同样事情的方法.

However, I'm now facing the following problem: A special case exists where I have to process a serialized message, but I don't know whether it's a message of type A or type B. I have a working solution in C++ (shown below), but I failed to find a way to do the same thing in 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 字段,如下所示:

In C++ I'm using the reflection API to get access to the CommonSettings field like this:

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() 来获取我想要获取的字段的描述符.然后它使用反射来获取实际数据.getCommonBlock 可以处理类型 A、B 或任何未来类型的消息,只要 Common 字段保持在索引 3 处即可.

The method 'getCommonBlock' uses FindFieldByNumber() to get hold of the descriptor of the field I'm trying to get. Then it uses reflection to fetch the actual data. getCommonBlock can process messages of type A, B or any future type as long as the Common field remains located at index 3.

我的问题是:有没有办法在 Python 中做类似的事情?我一直在查看 Protobuf 文档,但不能想办法做到这一点.

My Question is: Is there a way to do a similar thing Python? I've been looking at the Protobuf documentation, but couldn't figure out a way to do it.

推荐答案

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

I know this is an old thread, but I'll respond anyway for posterity:

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

Firstly, as you know, it's not possible to determine the type of a protocol buffer message purely from its serialized form. The only information in the serialized form you have access to is the field numbers, and their serialized values.

其次,执行此操作的正确"方法是拥有一个包含两者的原型,例如

Secondly, the "right" way to do this would be to have a proto that contains both, like

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).

This way, there's no ambiguity: you just parse the same proto (Parent) every time.

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

Anyway, if it's too late to change that, what I recommend you do is define a new message with only the shared fields, like

message Shared {
   required int32  FormatVersion             = 1;
   optional bool   SomeFlag [default = true] = 2;
   optional Common CommonSettings            = 3;
}

然后您应该能够假装消息(AB)实际上是一个 Shared,并相应地解析它.未知字段将无关紧要.

You should then be able to pretend that the message (either A or B) is in fact a Shared, and parse it accordingly. The unknown fields will be irrelevant.

这篇关于Python中未知类型Protobuf消息的访问字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆