动态生成Protobuf消息时,如何通过描述符生成对应的消息类?
问题
基于《Dynamically create a new protobuf message》一文编写Python代码,动态生成包含两个int类型字段和一个string类型字段的Protobuf消息(用于动态数据服务器传输查询结果)。描述符创建正常,但在生成消息类时出错:
出错代码片段:
# Step 5: Create the message class factory = message_factory.MessageFactory(pool) DynamicMessageClass = factory.GetPrototype(message_descriptor) # 错误发生在此行
报错信息:
/Users/mark/g/private/lessons/proto_dynamic/g2.py:40: UserWarning: MessageFactory class is deprecated. Please use GetMessageClass() instead of MessageFactory.GetPrototype. MessageFactory class will be removed after 2024. DynamicMessageClass = factory.GetPrototype(message_descriptor) Traceback (most recent call last): File "/Users/mark/g/private/lessons/proto_dynamic/g2.py", line 40, in <module> DynamicMessageClass = factory.GetPrototype(message_descriptor) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/mark/miniconda3/lib/python3.11/site-packages/google/protobuf/message_factory.py", line 185, in GetPrototype return GetMessageClass(descriptor) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/mark/miniconda3/lib/python3.11/site-packages/google/protobuf/message_factory.py", line 70, in GetMessageClass concrete_class = getattr(descriptor, '_concrete_class', None) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: No message class registered for 'dynamic_package.DynamicMessage'
解决方案
根据警告提示,MessageFactory类已被废弃,需改用GetMessageClass()方法直接生成消息类,无需实例化MessageFactory。修改Step5的代码即可解决注册错误:
修改后的核心代码
# Step 5: Create the message class DynamicMessageClass = message_factory.GetMessageClass(message_descriptor)
完整修正代码
from google.protobuf import descriptor_pb2, descriptor_pool, message_factory # Step 1: Create the DescriptorProto for the message message_descriptor_proto = descriptor_pb2.DescriptorProto() message_descriptor_proto.name = "DynamicMessage" message_descriptor_proto.field.add( name="first_int", number=1, type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32, label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL, ) message_descriptor_proto.field.add( name="second_int", number=2, type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32, label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL, ) message_descriptor_proto.field.add( name="a_string", number=3, type=descriptor_pb2.FieldDescriptorProto.TYPE_STRING, label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL, ) # Step 2: Create a FileDescriptorProto including the DescriptorProto file_descriptor_proto = descriptor_pb2.FileDescriptorProto() file_descriptor_proto.name = "dynamic_message.proto" file_descriptor_proto.package = "dynamic_package" file_descriptor_proto.message_type.add().CopyFrom(message_descriptor_proto) # Step 3: Add the FileDescriptorProto to a DescriptorPool pool = descriptor_pool.DescriptorPool() file_descriptor = pool.Add(file_descriptor_proto) # Step 4: Retrieve the message descriptor by name from the DescriptorPool message_descriptor = pool.FindMessageTypeByName("dynamic_package.DynamicMessage") # Step 5: Create the message class DynamicMessageClass = message_factory.GetMessageClass(message_descriptor) # Step 6: Instantiate the message class and populate with data dynamic_message = DynamicMessageClass() dynamic_message.first_int = 123 dynamic_message.second_int = 456 dynamic_message.a_string = "Hello, World!" # Serialize the message to a byte string serialized_data = dynamic_message.SerializeToString() # Show the serialized data print(serialized_data)
说明
GetMessageClass()方法会自动完成消息类的注册与生成,解决了原代码中"No message class registered"的错误- 废弃的
MessageFactory类将在2024年后移除,使用GetMessageClass()是官方推荐的替代方案
内容的提问来源于stack exchange,提问作者Mark Harrison
相关产品推荐
相关产品推荐

