You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

动态生成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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 00:17:34