本教程提供了使用协议缓冲区的基本Python程序员介绍。通过创建一个简单的示例应用程序,它向您展示了如何
- 在
.proto
文件中定义消息格式。
- 使用协议缓冲区编译器。
- 使用Python协议缓冲区API写入和读取消息。
这不是在Python中使用协议缓冲区的全面指南。有关更多详细的参考信息,请参阅《协议缓冲区语言指南》,《Python API参考》,《Python生成的代码指南》和《编码参考》。
为什么要使用协议缓冲区?
我们将使用的示例是一个非常简单的“地址簿”应用程序,它可以在文件中读取和写入人们的联系方式。通讯录中的每个人都有一个姓名,一个ID,一个电子邮件地址和一个联系电话。
您如何像这样序列化和检索结构化数据?有几种方法可以解决此问题:
- 使用Python酸洗。这是默认方法,因为它已内置在该语言中,但是它不能很好地处理模式演变,如果需要与用C ++或Java编写的应用程序共享数据,也不能很好地工作。
- 您可以发明一种将数据项编码为单个字符串的临时方法,例如将4个整数编码为“ 12:3:-23:67”。尽管确实需要编写一次性编码和解析代码,但是这是一种简单且灵活的方法,而且解析带来的运行时成本很小。这对于编码非常简单的数据最有效。
- 将数据序列化为XML。由于XML是人类(一种)可读的,并且存在用于多种语言的绑定库,因此这种方法可能非常有吸引力。如果要与其他应用程序/项目共享数据,这可能是一个不错的选择。但是,众所周知,XML占用大量空间,对它进行编码/解码会给应用程序带来巨大的性能损失。同样,导航XML DOM树比通常导航类中的简单字段要复杂得多。
协议缓冲区是解决此问题的灵活,高效,自动化的解决方案。使用协议缓冲区,您可以编写.proto
要存储的数据结构的描述。由此,协议缓冲区编译器创建了一个类,该类以有效的二进制格式实现协议缓冲区数据的自动编码和解析。生成的类为构成协议缓冲区的字段提供了获取器和设置器,并以协议为单位来处理读写协议缓冲区的细节。重要的是,协议缓冲区格式支持以某种方式扩展格式的思想,以使代码仍可以读取以旧格式编码的数据。
在哪里可以找到示例代码
示例代码包含在源代码包中的“ examples”目录下。 在这里下载。
要创建地址簿应用程序,您需要从.proto
文件开始。.proto
文件中的定义很简单:您为要序列化的每个数据结构添加一条消息,然后为消息中的每个字段指定名称和类型。这是.proto
定义您的消息的文件addressbook.proto
。
syntax = "proto2";
package tutorial;
message Person {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
optional string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
如您所见,语法类似于C ++或Java。让我们浏览文件的每个部分,看看它的作用。
该.proto
文件以程序包声明开头,这有助于防止不同项目之间的命名冲突。在Python中,包通常由目录结构决定,因此package
您在.proto
文件中定义的包不会对生成的代码产生影响。但是,您仍然应该声明一个以避免在协议缓冲区名称空间以及非Python语言中的名称冲突。
接下来,您将拥有消息定义。消息只是包含一组类型字段的汇总。许多标准的简单数据类型都可以作为字段类型,包括bool
,int32
,float
,double
,和string
。您还可以通过使用其他消息类型作为字段类型来为消息添加更多结构-在上述示例中,Person
消息包含PhoneNumber
消息,而AddressBook
消息包含Person
消息。您甚至可以定义嵌套在其他消息内的消息类型-如您所见,该PhoneNumber
类型在内部定义Person
。enum
如果您希望某个字段具有一个预定义的值列表之一,也可以定义类型-在这里您要指定电话号码可以是MOBILE
,HOME
或WORK
。
每个元素上的“ = 1”,“ = 2”标记标识该字段在二进制编码中使用的唯一“标记”。标签编号1至15与较高的编号相比,编码所需的字节减少了一个字节,因此,为了进行优化,您可以决定将这些标签用于常用或重复的元素,而将标签16和更高的标签用于较少使用的可选元素。重复字段中的每个元素都需要重新编码标签号,因此重复字段是此优化的最佳候选者。
每个字段都必须使用以下修饰符之一进行注释:
optional
:可能会或可能不会设置该字段。如果未设置可选字段值,则使用默认值。对于简单类型,您可以指定自己的默认值,就像type
在示例中为电话号码所做的那样。否则,将使用系统默认值:数字类型为零,字符串为空字符串,布尔值为false。对于嵌入式消息,默认值始终是消息的“默认实例”或“原型”,没有设置任何字段。调用访问器以获取未显式设置的可选(或必填)字段的值始终会返回该字段的默认值。
repeated
:该字段可以重复任意次(包括零次)。重复值的顺序将保留在协议缓冲区中。将重复字段视为动态大小的数组。
required
:必须提供该字段的值,否则该消息将被视为“未初始化”。序列化未初始化的消息将引发异常。解析未初始化的消息将失败。除此之外,必填字段的行为与可选字段完全相同。
永远是必需的 您将字段标记为时应非常小心required
。如果您希望停止写入或发送必填字段,则将字段更改为可选字段会很麻烦–老读者会认为没有该字段的邮件是不完整的,可能会无意中拒绝或丢弃它们。您应该考虑为缓冲区编写特定于应用程序的自定义验证例程。在Google内部,required
强烈反对使用字段;proto2语法中定义的大多数消息仅使用optional
并且repeated
。(Proto3根本不支持required
字段。)
您.proto
可以在“协议缓冲区语言指南”中找到有关编写文件的完整指南,包括所有可能的字段类型。但是,不要去寻找类似于类继承的工具–协议缓冲区不能做到这一点。
编译协议缓冲区
既然有了.proto
,接下来需要做的就是生成读取和写入AddressBook
(以及因此Person
和PhoneNumber
)消息所需的类。要做到这一点,你需要运行协议缓冲编译器protoc
对您.proto
:
- 如果尚未安装编译器,请下载软件包并按照README中的说明进行操作。
- 现在运行编译器,指定源目录(应用程序的源代码所在的位置;如果不提供值,则使用当前目录),目标目录(您希望生成的代码进入的位置;通常与相同
$SRC_DIR
)以及通向您的道路.proto
。在这种情况下,您...:
protoc -I=$SRC_DIR --python_out=$DST_DIR $SRC_DIR/addressbook.proto
因为您需要Python类,所以可以使用该--python_out
选项–其他受支持的语言也提供了类似的选项。
这将addressbook_pb2.py
在您指定的目标目录中生成。
协议缓冲区API
与生成Java和C ++协议缓冲区代码时不同,Python协议缓冲区编译器不会直接为您生成数据访问代码。相反(如您所见,您会看到addressbook_pb2.py
它)为所有消息,枚举和字段以及一些神秘的空类生成特殊的描述符,每种消息类型一个:
协议缓冲区基础:Python
原文:https://www.cnblogs.com/a00ium/p/14128887.html