【问题标题】:How to list attributes that you defined in google protocol buffers?如何列出您在 google 协议缓冲区中定义的属性?
【发布时间】:2014-11-04 17:32:20
【问题描述】:

我有一个类似于以下内容的 google 协议缓冲区定义:

message Foo {
   required string Name = 1;
   optional string Address = 2;
   optional string NickName = 3;
   optional  int32  height = 4;
}

现在在 python 中,我想列出上面的所有属性,但只列出那些属性。但是,交互式python,我看到谷歌定义了更多的字段。所以这似乎有问题。

我查看了一些关于自省的 stackoverflow 帖子。有一个看起来不错的检查模块,但问题是 google 协议缓冲区为我定义的其他成员。

有办法吗?

这就是我想做的事情。我有一个 python 实用程序,可以从命令行填写上述字段。我使用 argparse,我会:

parser = argparse.ArgumentParser(...)
parser.add_argument( "--attribute_name", blah)

我想将 add_argument() 放在一个循环中,并根据 proto 文件定义使其动态化。基本上,我不想在每次更改 proto 文件时继续修改实用程序的代码。看来我应该能够在 python 中做到这一点。我只是不知道怎么做。

有人有什么建议吗?

谢谢。

为了更多的信息,我拿了上面的例子,并用 protoc 编译它。这是交互式输出:

>>> import hello_pb2
>>> h = hello_pb2.Foo()
>>> dir(h)
['ADDRESS_FIELD_NUMBER', 'Address', 'ByteSize', 'Clear', 'ClearExtension', 'ClearField', 'CopyFrom', 'DESCRIPTOR', 'FindInitializationErrors', 'FromString', 'HEIGHT_FIELD_NUMBER', 'HasExtension', 'HasField', 'IsInitialized', 'ListFields', 'MergeFrom', 'MergeFromString', 'NAME_FIELD_NUMBER', 'NICKNAME_FIELD_NUMBER', 'Name', 'NickName', 'ParseFromString', 'RegisterExtension', 'SerializePartialToString', 'SerializeToString', 'SetInParent', '_InternalParse', '_InternalSerialize', '_Modified', '_SetListener', '__class__', '__deepcopy__', '__delattr__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__unicode__', '__weakref__', '_cached_byte_size', '_cached_byte_size_dirty', '_decoders_by_tag', '_extensions_by_name', '_extensions_by_number', '_fields', '_is_present_in_parent', '_listener', '_listener_for_children', 'height']

我检查了一些有前途的领域,比如 _fields,但那是空的。

这是答案:(由 Kenton Varda 的回复给出)

import hello_pb2
h = hello_pb2.Foo()
f = hello_pb2.Foo()
f.DESCRIPTOR.fields_by_name.keys()

【问题讨论】:

  • 你可以去掉所有以'_'开头的属性,以及所有的函数。这些都将由类定义,而不是参数。这可能会给您留下用户定义的字段以及一些标准。不同用户定义的标准相同。
  • 感谢您的建议。这也是一个好方法,但我只想要我定义的字段。这是一个很好的备份计划。
  • 你的协议版本是什么?

标签: python protocol-buffers argparse introspection


【解决方案1】:

您想遍历Foo.DESCRIPTOR.fields。见Descriptor 类:

https://developers.google.com/protocol-buffers/docs/reference/python/google.protobuf.descriptor.Descriptor-class

每个消息类都有一个静态成员DESCRIPTOR,它是该类型的描述符。

【讨论】:

  • 是的,你是对的。谢谢!你怎么这么快就找到了?
  • 我编写了 Google 的大部分开源 protobuf 代码。 :)
  • 谢谢你的技术。我们现在在我的公司广泛使用它。
  • 我可以通过dir() 使用protobuf 2.x 的消息直接查看所有属性。这是 protobuf 3.x 的问题吗?
  • 在 python3 中有与 @nn0p 相同的问题我看不到任何带有 dir() 的字段,想知道如何使 dir() 工作。
【解决方案2】:

如果要将 protobuf 对象转换为字典:

import hello_pb2

def proto2dict(msg):
    hsh_val = dict(msg.ListFields())
    d = dict((k, hsh_val[hsh]) for k, hsh in msg.DESCRIPTOR.fields_by_name.items())
    return d

data = {"Name":"name", "Address":"address", "NickName":"nick", "height": 6}
msg = hello_pb2.Foo(**data)

assert proto2dict(msg) == data

注意:看起来效率低下,可能不适用于嵌套定义。

【讨论】:

    【解决方案3】:

    在 proto3 上,我无法让 @Kenton Varda 回答工作。

    这对我有用:

    from hello_pb2 import Foo
    
    Foo.DESCRIPTOR.values_by_name
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 2010-09-25
      • 2010-11-28
      • 1970-01-01
      • 1970-01-01
      • 2012-05-03
      相关资源
      最近更新 更多