如何获取 protobuf 消息中定义的变量类型?
How to get the type of a variable defined in a protobuf message?
我正在尝试使用 Python 从 protobuf 文件到 Objective-C classes 做一些 'translation'。例如,给定 protobuf 消息:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}
我想把它翻译成objc class:
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int ID;
@property (nonatomic, copy) NSString *email;
@end
关键是获取每个属性的名称和类型。例如protobuf消息中的'optional string email',它的名字是'email',类型是'string',所以它应该是objective-c中的NSString *email。我按照官方教程,写了一个和教程里一样的addressbook.proto,然后编译。然后我写了我的 python 代码:
import addressbook_pb2 as addressbook
p = addressbook.Person()
all_fields = p.DESCRIPTOR.fields_by_name
# print "all fields: %s" %all_fields
field_keys = all_fields.keys()
# print "all keys: %s" %field_keys
for key in field_keys:
one_field = all_fields[key]
print one_field.label
这刚给了我:
1
2
3
2
所以我想标签不是我需要的,而 field_keys 只是我期望的名称列表。我尝试了一些其他词,并在网络上进行了一些搜索,但没有找到正确的答案。
如果没有办法获取类型,我还有一个想法,就是用纯'Pythonic'的方式读取和分析protobuf源文件的每一行,但我真的不想如果没有必要,请执行此操作。
有人可以帮我吗?
感谢 Marc 的回答,我找到了一些解决方案。这只是一个想法,但对我来说是一大步。
Python代码:
import addressbook_pb2 as addressbook
typeDict = {"1":"CGFloat", "2":"CGFloat", "3":"NSInteger", "4":"NSUinteger", "5":"NSInteger", "8":"BOOL", "9":"NSString", "13":"NSUinteger", "17":"NSInteger", "18":"NSInteger"}
attrDict = {"CGFloat":"assign", "NSInteger":"assign", "NSUinteger":"assign", "BOOL":"assign", "NSString":"copy"}
p = addressbook.Person()
all_fields = p.DESCRIPTOR.fields_by_name
field_keys = all_fields.keys()
for key in field_keys:
one_field = all_fields[key]
typeNumStr = str(one_field.type)
className = typeDict.get(typeNumStr, "NSObject")
attrStr = attrDict.get(className, "retain")
propertyStr = "@property (nonatomic, %s) %s *%s" %(attrStr, className, key)
print propertyStr
对于地址簿示例,它打印:
@property (nonatomic, copy) NSString *email
@property (nonatomic, copy) NSString *name
@property (nonatomic, retain) NSObject *phone
@property (nonatomic, assign) NSInteger *id
不是最终的解决方案,但意义重大。谢谢你,马克!
FieldDescriptor class 有一个 message_type
成员,如果是复合字段,它是该字段中包含的消息类型的描述符。否则,这是 None.
将此与遍历 DESCRIPTORS
的字典相结合意味着您可以获得复合和非的 name 和 type -复合(原始)字段。
import addressbook_pb2 as addressbook
DESCRIPTORS = addressbook.Person.DESCRIPTOR.fields_by_name
for (field_name, field_descriptor) in DESCRIPTORS.items():
if field_descriptor.message_type:
# Composite field
print(field_name, field_descriptor.message_type.name)
else:
# Raw type
print(field_name, field_descriptor.type)
# TYPE_DOUBLE
# TYPE_FLOAT
# TYPE_INT64
# TYPE_UINT64
# TYPE_INT32
# TYPE_FIXED64
# TYPE_FIXED32
# TYPE_BOOL
# TYPE_STRING
# TYPE_GROUP
# TYPE_MESSAGE
# TYPE_BYTES
# TYPE_UINT32
# TYPE_ENUM
# TYPE_SFIXED32
# TYPE_SFIXED64
# TYPE_SINT32
# TYPE_SINT64
# MAX_TYPE
原始类型是 class 个属性; https://github.com/protocolbuffers/protobuf/blob/master/python/google/protobuf/descriptor.py
我正在尝试使用 Python 从 protobuf 文件到 Objective-C classes 做一些 'translation'。例如,给定 protobuf 消息:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}
我想把它翻译成objc class:
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int ID;
@property (nonatomic, copy) NSString *email;
@end
关键是获取每个属性的名称和类型。例如protobuf消息中的'optional string email',它的名字是'email',类型是'string',所以它应该是objective-c中的NSString *email。我按照官方教程,写了一个和教程里一样的addressbook.proto,然后编译。然后我写了我的 python 代码:
import addressbook_pb2 as addressbook
p = addressbook.Person()
all_fields = p.DESCRIPTOR.fields_by_name
# print "all fields: %s" %all_fields
field_keys = all_fields.keys()
# print "all keys: %s" %field_keys
for key in field_keys:
one_field = all_fields[key]
print one_field.label
这刚给了我:
1
2
3
2
所以我想标签不是我需要的,而 field_keys 只是我期望的名称列表。我尝试了一些其他词,并在网络上进行了一些搜索,但没有找到正确的答案。
如果没有办法获取类型,我还有一个想法,就是用纯'Pythonic'的方式读取和分析protobuf源文件的每一行,但我真的不想如果没有必要,请执行此操作。
有人可以帮我吗?
感谢 Marc 的回答,我找到了一些解决方案。这只是一个想法,但对我来说是一大步。
Python代码:
import addressbook_pb2 as addressbook
typeDict = {"1":"CGFloat", "2":"CGFloat", "3":"NSInteger", "4":"NSUinteger", "5":"NSInteger", "8":"BOOL", "9":"NSString", "13":"NSUinteger", "17":"NSInteger", "18":"NSInteger"}
attrDict = {"CGFloat":"assign", "NSInteger":"assign", "NSUinteger":"assign", "BOOL":"assign", "NSString":"copy"}
p = addressbook.Person()
all_fields = p.DESCRIPTOR.fields_by_name
field_keys = all_fields.keys()
for key in field_keys:
one_field = all_fields[key]
typeNumStr = str(one_field.type)
className = typeDict.get(typeNumStr, "NSObject")
attrStr = attrDict.get(className, "retain")
propertyStr = "@property (nonatomic, %s) %s *%s" %(attrStr, className, key)
print propertyStr
对于地址簿示例,它打印:
@property (nonatomic, copy) NSString *email
@property (nonatomic, copy) NSString *name
@property (nonatomic, retain) NSObject *phone
@property (nonatomic, assign) NSInteger *id
不是最终的解决方案,但意义重大。谢谢你,马克!
FieldDescriptor class 有一个 message_type
成员,如果是复合字段,它是该字段中包含的消息类型的描述符。否则,这是 None.
将此与遍历 DESCRIPTORS
的字典相结合意味着您可以获得复合和非的 name 和 type -复合(原始)字段。
import addressbook_pb2 as addressbook
DESCRIPTORS = addressbook.Person.DESCRIPTOR.fields_by_name
for (field_name, field_descriptor) in DESCRIPTORS.items():
if field_descriptor.message_type:
# Composite field
print(field_name, field_descriptor.message_type.name)
else:
# Raw type
print(field_name, field_descriptor.type)
# TYPE_DOUBLE
# TYPE_FLOAT
# TYPE_INT64
# TYPE_UINT64
# TYPE_INT32
# TYPE_FIXED64
# TYPE_FIXED32
# TYPE_BOOL
# TYPE_STRING
# TYPE_GROUP
# TYPE_MESSAGE
# TYPE_BYTES
# TYPE_UINT32
# TYPE_ENUM
# TYPE_SFIXED32
# TYPE_SFIXED64
# TYPE_SINT32
# TYPE_SINT64
# MAX_TYPE
原始类型是 class 个属性; https://github.com/protocolbuffers/protobuf/blob/master/python/google/protobuf/descriptor.py