如何获取protobuf扩展属性的类型?

2024-09-22 20:18:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个构建系统,它必须从用户的输入中打包protobuf。用户在表单中填写字段,提交它们,然后构建系统打包protobuf并将它们发送。生成系统必须不知道它正在处理的类型。否则,每次项目团队更改他们的.proto时,我都必须进行构建更改来支持它们。在

绝大多数作品都是这样的。.protos可能是这样的:

#dataobj_base.proto
message DataObj {
  extensions 100 to 199;
  optional string property1 = 1;
}

#dataobj.proto
message DataObjExtension {
  optional string ext_property1 = 1;
}  

extend DataObj {
  optional DataObjExtension generic_extension = 100;
}

……这很简单,可以支持。到目前为止,我的构建系统已经通过知道它正在写入的类型的名称来访问泛型的扩展对象,而不需要更多。我可以导入DataObj_pb2和DataObjExtension_pb2并按如下方式使用它们:

^{pr2}$

这很好用,但是项目团队希望从同一个基础派生出多个类型。如果我需要两种不同的类型来处理DataObj“base”,它就会中断。我希望能够这样做:

extend DataObj {
  optional SomeOtherBaseObj generic_extension = 100;
}

问题是,在python代码中,我需要知道generic_extension的类型。如果我用我正在处理的类型的知识编写代码,我会:

extensions = instance.Extensions[SomeOtherBaseObj_pb2.generic_extension]

…而且extensions.__class__会告诉我我需要知道的一切。在

有没有一种方法可以在不知道扩展名中任何属性的名称的情况下(尤其是)知道它们的类型信息吗?我有很多方法可以重新设计.protos,使之成为一个巨大的改进,但是已经有相当多的代码基础依赖于它们本身。我可能不太可能在结构上做一些小的修改,但是我不可能销售。在

即使我能得到一份分房的清单,我也会很高兴的。我会这样做的:

extend DataObj {
  optional SomeOtherBaseObj generic_extension = 100;
  optional bool generic_extension_type__SomeOtherBaseObj = 101;
}

泛型扩展名类型。。。会无缘无故地出现在那里,除了给我泛型扩展名的类型名。不过,如果我能做到这一点,我可以简化为:

extend DataObj {
  optional SomeOtherBaseObj generic_extension__SomeOtherBaseObj = 100;
}

Tags: 代码用户类型系统extensionextensionsoptionalgeneric
1条回答
网友
1楼 · 发布于 2024-09-22 20:18:22

instance.ListFields()列出消息实例上设置的所有字段,包括扩展名。列表中的每个项都是^{}的元组,它包含完整的类型信息和字段值。(FieldDescriptor也是您将用作Extensions映射的键)因此您可以执行以下操作:

for field, value in instance.ListFields():
  assert value == instance.Extensions[field]
  print field.full_name, value

如果要查找邮件中尚未包含的扩展名,可以选择以下几种方法:

  1. DataObj._extensions_by_name是一个dict映射,将符号名(如my_pkg.generic_extension)映射到相应扩展的FieldDescriptors。

  2. DataObj._extensions_by_number是一个dict映射字段号(在您的例子中是100到199)到对应扩展名的FieldDescriptors。

当然,您可以迭代任意一个dict来了解所有已知的扩展。在

不幸的是,这两个技术上都是私有的,这意味着它们可能在未来的版本中崩溃。目前没有公共接口。但是,这些成员从第一个版本就已经存在了,并且存在于纯Python和支持C扩展的实现中。此外,proto3中的整个“扩展”功能都被删除了,所以担心这个接口会消失似乎是没有意义的。在

还要注意,依赖这些“全球注册中心”被认为不是一个好的设计。一个更好的设计应该是初始化组件的代码传递一个它需要知道的所有扩展的列表。一些高级代码应该轮询程序的其他组件,询问它们需要哪些扩展,构建一个详尽的列表,然后将其传入。这种方法使我们更容易知道哪些扩展在某处实际使用,而哪些扩展是可以删除的“死代码”。然而,我认识到,现有的代码库并不总是写得那么好,因此“以正确的方式”实现事情可能会比它值得的麻烦更多。在

相关问题 更多 >