我有一个Google协议缓冲区定义,看起来像以下机翼:
message Foo {
required string Name = 1;
optional string Address = 2;
optional string NickName = 3;
optional int32 height = 4;
}
现在使用python,我想列出以上所有属性,但仅列出那些属性。但是,在交互式python中,我看到Google定义了很多其他字段。因此,这似乎有问题。
我已经看过一些关于内省的stackoverflow帖子。有一个检查模块看起来不错,但是问题是Google协议缓冲区为我定义的其他成员。
有办法吗?
这是我想做的。我有一个python实用程序,可从命令行填写上述字段。我使用argparse,我将:
parser = argparse.ArgumentParser(...)
parser.add_argument( "--attribute_name", blah)
我想将add_argument()放在一个循环中,并根据原始文件定义使其动态。基本上,每次更改原型文件时,我都不想继续修改实用程序的代码。看来我应该能够在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()
您要遍历Foo.DESCRIPTOR.fields
。参见Descriptor
类:
每个消息类都有一个静态成员DESCRIPTOR
,它是该类型的描述符。
如果要将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
注:看起来效率低下,可能不适用于嵌套定义。