在python中使用protobuf
By 青衣极客 Blue Geek In 2019-09-19
使用caffe做深度学习研究的或者在大型互联网公司工作的朋友应该都是知道protobuf这个工具的。因为在通讯效率和代码兼容上的优点,protobuf被很多企业用于网络模块之间的通信。譬如在模块A中请求模块B,如果不使用protobuf这样的规范协议,而采用json这样随意的协议,那么在使用端就需要进行非常多的数据校验,以满足数据的有效性要求。如果有某个地方的检查稍有疏漏,则很容易造成整个产品线宕机。
对于数据格式的严格定义可以在很大程度上简化代码,也更具安全性。特别是protobuf对新增字段的友好对于迭代更新快速的网络服务而言是一大福音。python程序由于其简易性,导致很多朋友在编写python程序时十分随意,这给python代码的维护带来了极大的挑战。如果在python项目中引入protobuf来对基础的数据结构进行规范化,将极大节省维护成本和人员精力。本文简要描述一下在python中使用protobuf的流程,大家可以在熟悉流程之后深入探索protobuf,这是一个非常流行而有用的协议工具。
# 查看python所安装的protobuf的版本
!python3 -c "import google.protobuf as protobuf;print(protobuf.__version__)"
3.7.0
1. 编写proto文件定义数据结构
编写proto文件定义数据结构 首先需要编写proto文件。该文件有独立的编写语法。总体上格式与C语言比较相似,但是语法更加简单,基本一看就会。这里给一个例子让大家熟悉一下。
在这个文件中定义了一个Person的数据机构,这个数据结构有四个成员,每个成员都有一个标号。之后每次添加新成员的标号都要与之前不同。
# 编写proto文件,定义数据结构
!cat ../../proto/test.proto
syntax = "proto3";
message Person{
int32 year = 1;
float height = 2; // cm
float weight = 3; // kg
string id = 4;
}
2. 编译proto文件
编译proto文件 proto文件编写完成之后需要进行编译,以产出对应语言的源码文件。这里演示一些编译产出python文件。 由于有一些封装类型的代码,导致编译产生的python文件比较庞杂,我们只需要知道自己定义的数据结构被编译成一个同名的类即可。
# 编译proto文件,生成对应的python代码
!protoc --python_out=../../output -I=../../proto test.proto
!ls ../../output/
mpl.png np_save.npy test_pb2.py
3. 导入模块
导入模块 导入一些必要的模块和刚才定义并编译生成的数据结构。由于编译生成的python文件不在当前的可搜索空间之后,因此需要在导模块时设置路径,以便正常导入。
# 导入可能需要的一些模块
import os
import sys
# 将proto生成的python文件所在目录添加到搜索目录
sys.path.append('../../output')
# 到入编写的Person数据结构
from test_pb2 import Person
4. 创建对象
创建对象 当Person类导入进来之后,就可以利用这个类来构造对象和设置成员。当然这个类也提供了一些函数来进行操作。将这个对象直接打印出来,可以发现自己设置的属性值,而且格式是key-value形式的。
# 创建Person对象,并设置属性
p = Person()
p.year = 18
p.height = 170
p.weight = 60
p.id = '1234567890'
print(p)
year: 18
height: 170.0
weight: 60.0
id: "1234567890"
5. 序列化
序列化 protobuf的一大作用是将数据结构进行高效率的序列化,生成字符串然后用于网络传输。这里演示一下序列化函数的调用,以及序列化结果的内容。
# 将Person对象进行序列化
p_str = p.SerializeToString()
print(p_str)
b'\x08\x12\x15\x00\x00*C\x1d\x00\x00pB"\n1234567890'
6. 反序列化
反序列化 那么能不能根据这个序列化得到的字符串反序列化出数据对象呢?答案是肯定的。下面就演示一下从字符串转换到数据对象的方法。
# 通过反序列化从字符串恢复Person对象
p1 = Person()
p1.ParseFromString(p_str)
print(p1)
year: 18
height: 170.0
weight: 60.0
id: "1234567890"
通过以上6个步骤就可以熟悉在python中使用protobuf的基本方法,但是要想精通protobuf还需要好好熟悉proto的语法、原理,还需要大量应用才能感受到它所带来的便利。

COMMENT
博客评论区功能由Github Issue提供,提交Issue时请以本文标题为话题。
"BG10-在python中使用protobuf"