生成的Protobuf Python类异常,无法进行序列化与解析操作
问题描述
我正在尝试Protobuf官方Python教程的首个示例,这是我的.proto文件:
syntax = "proto2"; package tutorial; message Person { optional string name = 1; optional int32 id = 2; optional string email = 3; enum PhoneType { PHONE_TYPE_UNSPECIFIED = 0; PHONE_TYPE_MOBILE = 1; PHONE_TYPE_HOME = 2; PHONE_TYPE_WORK = 3; } message PhoneNumber { optional string number = 1; optional PhoneType type = 2 [default = PHONE_TYPE_HOME]; } repeated PhoneNumber phones = 4; } message AddressBook { repeated Person people = 1; }
我在终端进入该proto文件所在目录,执行了编译命令:
protoc --python_out=../Generated addressbook.proto
生成的addressbook_pb2.py内容如下:
# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: addressbook.proto # Protobuf Python Version: 4.25.2 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11\x61\x64\x64ressbook.proto\x12\x08tutorial\"\xa3\x02\n\x06Person\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\x05\x12\r\n\x05\x65mail\x18\x03 \x01(\t\x12,\n\x06phones\x18\x04 \x03(\x0b\x32\x1c.tutorial.Person.PhoneNumber\x1aX\n\x0bPhoneNumber\x12\x0e\n\x06number\x18\x01 \x01(\t\x12\x39\n\x04type\x18\x02 \x01(\x0e\x32\x1a.tutorial.Person.PhoneType:\x0fPHONE_TYPE_HOME\"h\n\tPhoneType\x12\x1a\n\x16PHONE_TYPE_UNSPECIFIED\x10\x00\x12\x15\n\x11PHONE_TYPE_MOBILE\x10\x01\x12\x13\n\x0fPHONE_TYPE_HOME\x10\x02\x12\x13\n\x0fPHONE_TYPE_WORK\x10\x03\"/\n\x0b\x41\x64\x64ressBook\x12 \n\x06people\x18\x01 \x03(\x0b\x32\x10.tutorial.Person') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'addressbook_pb2', _globals) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None _globals['_PERSON']._serialized_start=32 _globals['_PERSON']._serialized_end=323 _globals['_PERSON_PHONENUMBER']._serialized_start=129 _globals['_PERSON_PHONENUMBER']._serialized_end=217 _globals['_PERSON_PHONETYPE']._serialized_start=219 _globals['_PERSON_PHONETYPE']._serialized_end=323 _globals['_ADDRESSBOOK']._serialized_start=325 _globals['_ADDRESSBOOK']._serialized_end=372 # @@protoc_insertion_point(module_scope)
但我在生成的文件里找不到可用的类,不清楚怎么用这个文件做数据序列化和解析。
解决方法
生成的Python文件中,类是通过_builder动态构建的,所以源码里看不到显式的类定义,但导入后就能直接使用。以下是具体的使用示例:
1. 导入生成的模块
确保../Generated目录在Python的sys.path中,然后导入:
import addressbook_pb2
2. 创建实例并赋值
# 创建AddressBook实例 address_book = addressbook_pb2.AddressBook() # 创建Person实例并添加到AddressBook person = address_book.people.add() person.name = "Alice" person.id = 1234 person.email = "alice@example.com" # 添加电话号码 phone = person.phones.add() phone.number = "123-456-7890" phone.type = addressbook_pb2.Person.PHONE_TYPE_MOBILE phone2 = person.phones.add() phone2.number = "987-654-3210" # 不指定type的话会使用默认值PHONE_TYPE_HOME
3. 序列化数据
把对象序列化成二进制字节流:
serialized_data = address_book.SerializeToString() # 可以把serialized_data写入文件或通过网络传输
4. 解析二进制数据
从字节流还原成对象:
# 假设serialized_data是接收到的二进制数据 new_address_book = addressbook_pb2.AddressBook() new_address_book.ParseFromString(serialized_data) # 访问解析后的数据 for person in new_address_book.people: print(f"Name: {person.name}") print(f"ID: {person.id}") print(f"Email: {person.email}") for phone in person.phones: type_name = addressbook_pb2.Person.PhoneType.Name(phone.type) print(f"Phone ({type_name}): {phone.number}")
关键说明
- 生成的类名和你
.proto文件中定义的message/enum一一对应,比如Person、AddressBook、Person.PhoneNumber、Person.PhoneType。 - 对于
repeated字段,使用add()方法添加新元素,就像示例中address_book.people.add()和person.phones.add()。 - 序列化用
SerializeToString(),解析用ParseFromString(),这是Protobuf Python API的标准方法。
内容的提问来源于stack exchange,提问作者HENSEL WILSON GOVEAS
相关产品推荐
相关产品推荐

