Python Protobuf 使用

Protocol Buffer Serialization 指的是使用 Protocol Buffer 进行数据序列化的过程。在这个过程中,结构化的数据被转换成 Protocol Buffer 的二进制格式、文本 json 格式,以便于存储、传输或者在不同的系统之间进行交换。

Protocol Buffer Serialization 的优点包括序列化后数据的紧凑性、高效性以及跨语言、跨平台的兼容性。这使得它成为许多分布式系统和网络通信中的首选序列化方法之一。

项目:https://github.com/protocolbuffers/protobuf
文档:https://protobuf.dev/

1. Proto 编译

https://github.com/protocolbuffers/protobuf/releases 或者从右侧的网盘下载 protobuf 编译器,并将 bin 目录配置 PATH 环境变量中。

安装 Python protobuf 第三方库:

pip install protobuf==5.27.1 -i https://pypi.tuna.tsinghua.edu.cn/simple/

注意:protobuf 的编译器版本要和 python protobuf 库的版本要保持一致。我们 protoc 使用的是 27.1 版本,对应的 protobuf 的 5.27.1 版本。

syntax = "proto3";

enum Week
{
    Mon = 0;
    Tue = 1;
    Wed = 2;
    Thu = 3;
    Fri = 4;
    Sat = 5;
    Sun = 6;
}


message Custom
{
    int32 attr1 = 1;
    int32 attr2 = 2;
}

message Demo
{
    string name = 1;
    int32 numb = 2;
    Week week = 3;
    repeated int32 rept = 4;
    map<string, int32> mpsi = 5;
    Custom cust = 6;
}

当编写完数据定义相关的 .proto 文件,我们还需要使用 protobuf 编译器来生成对应语言的数据类文件。

Document:https://protobuf.dev/programming-guides/proto3/#generating

对于 Python,每个 proto 文件会生成两种不同的文件:

  • foo_pb2.py: 实际使用的模块文件
  • foo_pb2.pyi:编辑器可以根据 .pyi 文件提示可用的方法和属性

需要注意的是,默认 pyi 文件不会自动生成需要指定,需要指定 --python_out=pyi_out:输出路径

# 不生成 pyi 文件
protoc *.proto --python_out=.

# 生成 pyi 文件
protoc *.proto --python_out=pyi_out:. 

2. 对象序列化

在 Protobuf 中 SerializeToString 函数可以将 Python 数据对象序列化为二进制数据(字节类型),ParseFromString 函数可用以将二进制数据反序列化为 Python 数据对象。

from demo_pb2 import Demo, Week, Custom
from google.protobuf import json_format

# 1. 对象操作
def test01():

    demo = Demo()
    # 1. 基本类型
    demo.name = "张三"
    demo.numb = 200
    demo.week = Week.Thu

    # 2. 自定义类型
    demo.cust.attr1 = 100
    demo.cust.attr2 = 200

    # 3. repeated 类型
    demo.rept.append(10)
    demo.rept.append(20)
    demo.rept.insert(1, 30)

    # 4. map 类型
    demo.mpsi['k1'] = 100
    demo.mpsi['k2'] = 200
    demo.mpsi['k3'] = 300

    print(demo)

    # 5. 其他方法
    print('对象大小:', demo.ByteSize())

    # demo = Demo(name="张三",
    #             numb=100,
    #             week=Week.Thu,
    #             rept=[10, 20, 30],
    #             mpsi={'v1': 100, 'v2': 200},
    #             cust=Custom(attr1=11, attr2=22))


# 2. 对象序列化
def test02():

    demo = Demo(name='张三',
                numb=100,
                week=Week.Thu,
                rept=[10, 20],
                mpsi={'v1': 100, 'v2': 200},
                cust=Custom(attr1=11, attr2=22))

    # 1. 序列化为二进制数据
    data = demo.SerializeToString()
    print(data)
    open('data.bin', 'wb').write(data)

    # 2. 序列化为 json 格式
    json = json_format.MessageToJson(demo)
    print(json)
    open('data.json', 'w').write(json)


# 3. 对象反序列化
def test03():
    # 1. 反序列化二进制数据
    demo = Demo()
    data = open('data.bin', 'rb').read()
    demo.ParseFromString(data)
    print(demo)
    print('-' *  30)

    # 反序列化 json 数据
    data = open('data.json', 'r').read()
    demo = json_format.Parse(data, Demo())
    print(demo)


if __name__ == '__main__':
    test01()
    test02()
    test03()
未经允许不得转载:一亩三分地 » Python Protobuf 使用
评论 (0)

6 + 6 =