广告
返回顶部
首页 > 资讯 > 后端开发 > Python >在Python中使用protocol b
  • 162
分享到

在Python中使用protocol b

Pythonprotocol 2023-01-31 01:01:04 162人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

本教程提供了一个python程序员使用protocol buffers的基本的入门教程。通过创建一个简单的示例应用程序,它向您展示了如何 *在一个.proto文件中定义Message的格式。 *使用protocol buffer c

教程提供了一个python程序员使用protocol buffers的基本的入门教程。通过创建一个简单的示例应用程序,它向您展示了如何

*在一个.proto文件中定义Message的格式。

*使用protocol buffer compiler。

*使用Python protocol buffer api去读写Message。

这不是一个在Python中使用protocol buffers的一个全面的指南。如果想了解更详细的参考信息,请阅读 Protocol Buffer Language Guide,Python API Reference,Python Generated Code Guide和Encoding Reference。

Why Use Protocol Buffers?

我们将使用的示例是一个非常简单的“地址簿”应用程序,可以从一个文件中读写人们的联系方式。地址簿中的每个人都有一个名字,一个ID、一个电子邮件地址,和联系电话号码。

你怎样用这样方式序列化和检索结构数据?这里有一些办法可以解决这个问题:

*使用Python处理。这是默认的方法,因为这种方法是直接用到语言,但它不利于模式演变,还有,它不利于你共享数据给c++或Java写的应用。

*你可以发明一种特别的方式将数据项编码为一个字符串,如将4个int编码为“12:3:23:67”。这是一个简单的和灵活的方法,尽管它一次性需要编写编码和解析的代码,并为解析加上一个小小的运行成本。这方法最适合为非常简单的数据编码。

*用XML序列化数据。这种方法非常有吸引力,因为XML具有易读性,还有了许多库,用来支持各种语言。这是一个好选择,如果你想和其它应用/工程共享数据。但是,XML也是出了名的耗空间,还有,编码/解码会令应用程序性能产生巨大的损失。加上,操纵一个XML DOM树通常会比操纵类中的字段复杂。

Protocol buffers会灵活、高效、自动化解答来准确地解决这个问题。有了protocol buffers,你就可以编写一个.proto文件用来描述你想存储的数据结构。因此,protocol buffer编译器会创建一个类,实现自动编码和解析protocol buffer数据,通过一个高效的二进制格式。这个生成的类提供了getter和setter的字段组成一条protocol buffer,而且把读出和写入的细节当成protocol buffer的一个单元。更重要的,protocol buffer支持在日后里扩展格式这种想法,这样,代码仍然可以读取用旧的格式编码的数据。

Where to Find the Example Code

在源代码目录中,文件夹“examples”下包含所有的例程。Download it here.

Defining Your Protocol FORMat

为了创建你的“地址簿”应用,你会用到一个.proto文件。这是一个很简单的.proto文件定义:你可以为你想序列化的数据结构添加一条Message,然后在Message中为每个字段指定一个名称和一个类型。以下是你想为你的Message定义的.proto文件,addressbook.proto。

package tutorial;

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

message AddressBook {
  repeated Person person = 1;
}

如你所见,在语法上很像C++和Java。那就让我们看看文件中的每个部分和看看它们究竟是干什么的。

这个.proto文件开头是包的声明,为了帮助防止在不同的工程中命名冲突。在Python中,包通常由目录结构决定的,所以这个由你的.proto文件定义的包,在你生成你代码中是没有效果的。但是,你应该坚持声明这条语句,为了在protocol Buffers的命名空间中防止名子的冲突,就像其它非Python的语言那样。

然后,就是你定义的Message。一个Message是一个包含一组类型字段的集合。有许多简单的标准的数据类型可以用在类型字段中,包括bool,int32,float,double和string。你也可以使用更加多的结构来定义你的Message,例如用其它Message类型当作类型字段-在上面的例子PersonMessage中就包含了PhoneNumberMessage,还有AddressBookMessage包含PersonMessage。你也可以定义Message嵌入其它的Message——就如你所见到的那样,PhoneNumber类型就是在Person类型中定义的。你也可以定义一个枚举类型,如果你想你其中一个字段有一个预设的类型列表——在这里,你可以将你的电话号码列举为MOBILE,HOME或者WORK。

那个“=1”,“=2”标记每个元素的识别,作为二进制编码中字段的唯一的标签。标签要求数字1-15比更高的数字少一个字节编码,所以,作为最优化的方案,你可以决定对常用的和要重复使用的元素使用这些标签,把16或最高的数字留给不常用和可选择的元素。每个重复的字段里的元素要求重新编码它的标签号码,所以重复的字段特别适合使用这种优化。

每个字段一定要被以下的修饰语修饰:

*required:一定要提供一个值给这个字段,否则这条Message会被认为“没有初始化”。序列化一列没有初始化的Message会出现异常。 解析一条没有初始化的Message会失败。除此而外,这个required字段的行为更类似于一个optional字段。

*optional:这个字段可以设置也可以不设置 。如果一个可选字段没有设置值,会用缺省的值。简单来说,你可以指定自己的默认值,就像我们在例子中对phone number类型所做的。另外,系统会缺省这样做:0给整数类型,空串给字符串类型,false给布尔类型。对于嵌入的Message,缺省的值通常会是“默认实例”或“原型”,对那些没有设置字段的Message。调用存取器获得一个可选的(或要求)字段的值,那些通常什么明确给出值的字段总是返回该字段的默认值。

*repeated:这个字段会重复几次一些号码(包括0)。重复的值给按顺序保存在protocol buffer中。重复的字段会被认为是动态的数组

Required Is Forever 你应该非常小心地把字段标记为required。如果在某一时刻你希望停止写或发送一个必填字段,那就把不确定的字段更改为一个可选的字段——老的阅读器会认为没有这个字段Message是不完整的,而且可能会无意中拒绝或删除它们。你应该考虑为你的buffer编写特定于应用程序的自定义验证例程。一些来自Google有些结论:使用required弊大于利;他们更愿意只用optional和repeated。但是,这一观点并不普遍。

你会找到编写.proto文件的指南——包括所有可能的类型字段——在Protocol Buffer Language Guide.不要去找类似于类继承的设备,虽然——protocol buffers不这样做。

Compiling Your Protocol Buffers

现在你有了自己的.proto文件,下一件你需要去做的事就是生成你需要读写AddressBook(还带有Person和PhoneNumber)Message的类。为了完成这件工作,你需要运行protocol buffer 编译器protoc去编译你的.proto文件:

1.如果你没有安装编译器,download the package,按照在README的说明去做。

2.现在运行编译器,指定源目录(你的应用程序源码目录——如果你不提供这个目录,默认就是当前目录),目标目录(你的应用程序编译后生成的代码的目录;通常用$SRC_DIR),还有你.proto文件的目录路径。在这种情况下,你可以

protoc -I=$SRC_DIR --python_out=$DST_DIR $SRC_DIR/addressbook.proto

因为你想生成Python的类,所以你要用--python_out选项——也有类似的选项支持其它语言。

这样addressbook_pb2.py就会生成在你指定的目标目录中。

The Protocol Buffer API

不你你生成的Java或C++的protocol buffer代码,Python protocol buffer编译器不会直接生成你可以数据访问的代码。反而(就你看见的那样,如果你看了addressbook_pd2.py)它会为你的Message,枚举,字段生成指定的描述符,还有一些难以理解的空类,其中一段Message类型:

class Person(message.Message):
  __metaclass__ = reflection.GeneratedProtocolMessageType

  class PhoneNumber(message.Message):
    __metaclass__ = reflection.GeneratedProtocolMessageType
    DESCRIPTOR = _PERSON_PHONENUMBER
  DESCRIPTOR = _PERSON

class AddressBook(message.Message):
  __metaclass__ = reflection.GeneratedProtocolMessageType
  DESCRIPTOR = _ADDRESSBOOK

每个类中都有一些重要的语句:__metaclass__ = reflection.GeneratedProtocolMessageType.尽管Python中metaclasses是如何工作的详细信息超出了本教程的范围,你可以把它们看作是创建类的模板。在加载时,GeneratedProtocolMessageType  metaclass 会用指定的描述符创建所有你需要用到的Message类型的Python方法和添加和这些方法相关的类。然后你就可以在你的代码中使用这些类。

这一切的最终效果是,你可以使用Person类就像你定义的Message的基类,将它当作常规的字段。例如,你可以这样写:

import addressbook_pb2
person = addressbook_pb2.Person()
person.id = 1234
person.name = "John Doe"
person.email = "jdoe@example.com"
phone = person.phone.add()
phone.number = "555-4321"
phone.type = addressbook_pb2.Person.HOME

注意,这些赋值不仅仅是一个在通用的Python对象中添加任意的新字段。如果你尝试赋值一些值到.proto文件没有定义的字段变量中,会发生AttributeError 异常。如果你赋给一个字段错误的类型的值,会发生TypeError 异常。当然,同时,在看一个字段的值前,这个字段就已经设置为返回默认值。

person.no_such_field = 1  # raises AttributeError
person.id = "1234"        # raises TypeError

如果想知道更多关于protocol 编译器为特定定义字段生成的成员,请看Python generated code reference.

Enums

Enums是由metaclass扩展成一组具有符号常量的整数值。那么,举个例子,不变量addressbook_pb2.Person.WORK有一个值为2.

Standard Message Methods

每个Message类都包含一些其它方法让你检查或操作 entire message,包括:

IsInitialized(): 检查required字段是否都设置了值。 __str__(): 返回一个可读的message,对于调试尤其有用。(通常调用str(message)或打印message。) CopyFrom(other_msg): 用给出的message的值覆盖这个message Clear(): 清除所有元素,回到空状态。
这些方法是操作Message的接口,想了解更多,可以看complete API documentation for Message.

Parsing and Serialization

最后,每个protocol buffer类都有读message或写message的方法给你选择通过用protocol buffer binary format。包括:

  • SerializeToString(): 序列化这个message和以字符串的方式返回。 注意,这是二进行字节,不是一个文本; 我们只使用str类型作为一个方便的容器
  • ParseFromString(data): 从给出的字符串中解析一条message。
这里有只是一些使用解析和序列化的选项。此外,也会以看 Message API reference,查看完整的列表。

Protocol Buffers和O-O Design Protocol buffer 类基本上是dumb data holders(类似于C++的structs);它们在对象模型虽不做好first class citizens。如果你想为已生成的类添加丰富的行为,更好的方法是把已生成的protocol buffer类封装在一个特定于应用程序的类。封装protocol buffers是一个好想法,如果你不会控制.proto file的设计(如果说,你征用其它工程的代码)。在这种情况下,您可以使用封装类去制作接口会更适合您的应用程序,在独特环境中:隐藏一些数据和方法,暴露便利的函数,等等。你绝不应该添加行为通过继承已生成的类。这将打破内部机制和没有良好的面向对象的体验。

Writing A Message

现在可以尝试用你的protocol buffer 类了。首先你第一件事你想让你的地址簿应用程序能够做的事情就是把个人信息写到你的地址簿文件里。为此,你创建和填写你的protocol buffer类的实例,然后把它们写到输出流。
以下是从AddressBook文件中读一个程序,按用户的输入添加一个新Person,和写一个新AddressBook再一次返回这个文件。部分直接调用或引用的从protocol compiler生成的代码给出了高亮显示。
#! /usr/bin/python

import addressbook_pb2
import sys

# This function fills in a Person message based on user input.
def PromptForAddress(person):
  person.id = int(raw_input("Enter person ID number: "))
  person.name = raw_input("Enter name: ")

  email = raw_input("Enter email address (blank for none): ")
  if email != "":
    person.email = email

  while True:
    number = raw_input("Enter a phone number (or leave blank to finish): ")
    if number == "":
      break

    phone_number = person.phone.add()
    phone_number.number = number

    type = raw_input("Is this a mobile, home, or work phone? ")
    if type == "mobile":
      phone_number.type = addressbook_pb2.Person.MOBILE
    elif type == "home":
      phone_number.type = addressbook_pb2.Person.HOME
    elif type == "work":
      phone_number.type = addressbook_pb2.Person.WORK
    else:
      print "Unknown phone type; leaving as default value."

# Main procedure:  Reads the entire address book from a file,
#   adds one person based on user input, then writes it back out to the same
#   file.
if len(sys.argv) != 2:
  print "Usage:", sys.argv[0], "ADDRESS_BOOK_FILE"
  sys.exit(-1)

address_book = addressbook_pb2.AddressBook()

# Read the existing address book.
try:
  f = open(sys.argv[1], "rb")
  address_book.ParseFromString(f.read())
  f.close()
except IOError:
  print sys.argv[1] + ": Could not open file.  Creating a new one."

# Add an address.
PromptForAddress(address_book.person.add())

# Write the new address book back to disk.
f = open(sys.argv[1], "wb")
f.write(address_book.SerializeToString())
f.close()

Reading A Message

当然,一个地址簿,如果你不能从中得到任何信息,那也不会有多大用处!这个例子为从上面的示例读取文件并打印其所有信息。
#! /usr/bin/python

import addressbook_pb2
import sys

# Iterates though all people in the AddressBook and prints info about them.
def ListPeople(address_book):
  for person in address_book.person:
    print "Person ID:", person.id
    print "  Name:", person.name
    if person.HasField('email'):
      print "  E-mail address:", person.email

    for phone_number in person.phone:
      if phone_number.type == addressbook_pb2.Person.MOBILE:
        print "  Mobile phone #: ",
      elif phone_number.type == addressbook_pb2.Person.HOME:
        print "  Home phone #: ",
      elif phone_number.type == addressbook_pb2.Person.WORK:
        print "  Work phone #: ",
      print phone_number.number

# Main procedure:  Reads the entire address book from a file and prints all
#   the information inside.
if len(sys.argv) != 2:
  print "Usage:", sys.argv[0], "ADDRESS_BOOK_FILE"
  sys.exit(-1)

address_book = addressbook_pb2.AddressBook()

# Read the existing address book.
f = open(sys.argv[1], "rb")
address_book.ParseFromString(f.read())
f.close()

ListPeople(address_book)

Extending a Protocol Buffer

迟早你会发布使用protocol buffer的代码,毫无疑问你会想“改善” protocol buffer的定义。如果你想让你的新buffers 是向后兼容的,又或者你的旧buffers是向前兼容的-那你就肯定想这样做-那这里有些规则你需要遵守了。在新版本的protocol buffer中:
  • 你不能改变任何现有的标签数据字段。
  • 你不能添加或删除任何repeated的字段。
  • 你可以删除optional 或repeated 字段。
  • 你可以添加新的optional 或repeated 字段但你必须使用新的标签号码。(即在protocol buffer从来没有使用过的标记数字,甚至通过删除字段)
这些规则有一些例外,但他们很少使用
如果你遵守这些规则,旧的代码会很高兴地读新的messages并简单地忽略所有新字段。对于旧代码来说,被删除的可选optional 字段,简单地拥有它们的默认值,被删除的repeated字段会变为空。新代码会明显地读到旧代码。但是,记住,新的optional字段不会显示旧的message,所以你需要明确地检查它们是否有has_设置,又或者提供一个合理的缺省的值在[default = value]的标签数字后,在你的.proto文件上。如果没有为一个optional无线设置缺省的值,一个字符串的值会替代缺省的值,这个缺省的值则为一个空串。对于布尔类型来说,缺省为false。对于整型类型来说,缺省为0。还有记住,如果你添加一个新repeated字段,你的新代码将无法判断它是空的(通过新代码)或从未设置(旧代码)由于没有设置has_ flag给它。

本文翻译自:https://developers.google.com/protocol-buffers/docs/pythontutorial



--结束END--

本文标题: 在Python中使用protocol b

本文链接: https://www.lsjlt.com/news/184431.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 在Python中使用protocol b
    本教程提供了一个Python程序员使用protocol buffers的基本的入门教程。通过创建一个简单的示例应用程序,它向您展示了如何 *在一个.proto文件中定义Message的格式。 *使用protocol buffer c...
    99+
    2023-01-31
    Python protocol
  • location中assign与protocol如何使用
    本篇内容主要讲解“location中assign与protocol如何使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“location中assign与prot...
    99+
    2022-10-19
  • C++中Protocol Buffer怎么安装和使用
    要在C++中使用Protocol Buffer,您需要进行以下步骤来安装和使用它: 下载和安装 Protocol Buffer ...
    99+
    2023-10-23
    C++
  • MySQL中B+Tree如何使用
    本篇文章为大家展示了MySQL中B+Tree如何使用,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。B+ treeB+ tree 实际上是一颗m叉平衡查找树(不是二叉...
    99+
    2022-10-18
  • nginx中怎么配置使用proxy protocol协议
    本文小编为大家详细介绍“nginx中怎么配置使用proxy protocol协议”,内容详细,步骤清晰,细节处理妥当,希望这篇“nginx中怎么配置使用proxy protocol协议”文章能帮助大家解决疑惑,下面跟着小...
    99+
    2023-06-30
  • 使用python抓取B站数据的方法
    这篇文章给大家分享的是有关使用python抓取B站数据的方法的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。概述可以获取的数据包括:video-视频模块user-用户模块dynamic-动态模块这次用“Runnin...
    99+
    2023-06-15
  • 树结构中MongoDb使用的到底是 B 树还是B+树
    这篇文章给大家介绍树结构中MongoDb使用的到底是 B 树还是B+树,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。关于 B 树与 B+ 树,网上有一个比较经典的问题:为什么 Mong...
    99+
    2022-10-18
  • 【Python】使用Python做简易爬虫爬取B站评论
    目录 一、前言 二、分析网页 三、代码 1.头 2.获取根评论 3.获取子评论 四、总代码 五、总结 一、前言         B站评论没有查找功能,就随手写了一个爬虫爬取B站评论存储到本地txt中         首先需要安装pyth...
    99+
    2023-08-31
    python 爬虫 开发语言
  • nginx中配置使用proxy protocol协议的全过程
    目录简介proxy protocol在nginx中应用在nginx中配置使用proxy protocol在nginx中启用proxy protocol使用Real‑IP module...
    99+
    2022-11-13
  • 【Python】在python中使用MySQL
    文章目录 0 前言1 参考链接2 数据库概述3 MySQL配置3.1 下载及安装3.1.1 其他安装方式 3.2 环境配置3.3 基本使用3.4 问题解决3.4.1 如何重置密码3.4....
    99+
    2023-09-10
    mysql python 数据库 pymysql
  • MongoDB中使用 B树的原因是什么
    本篇文章给大家分享的是有关 MongoDB中使用 B树的原因是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。MongoDB 是一个通用的、...
    99+
    2022-10-18
  • B+树在数据库索引中的作用是什么
    本篇文章给大家分享的是有关B+树在数据库索引中的作用是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、B-树和B+树回顾1.B-树B-tree(多路搜索树)是一种常见的数...
    99+
    2023-06-19
  • Mysql InnoDB中B+树索引使用注意事项
    目录一、根页面万年不动二、内节点中目录项记录的唯一性三、一个页面至少容纳 2 条记录一、根页面万年不动 在之前的文章里,为了方便理解,都是先画存储用户记录的叶子节点,然后再画出存储目...
    99+
    2022-11-13
  • 在Python中使用regionprops
    在Python中,可以使用`regionprops`函数从二进制图像的连通区域中提取属性。下面是一个示例代码:```pythonim...
    99+
    2023-09-26
    Python
  • 在 Python 中使用 Elastic
    在这篇文章中,我将讨论 Elasticsearch 以及如何将其整合到不同的 Python 应用程序中。 什么是 ElasticSearch? ElasticSearch(ES)是一个建立在 Apache Lucene 之上的高度可用的分布...
    99+
    2023-01-31
    Python Elastic
  • 在Python中使用MySQL-
    PyMySQL的使用 安装 sudo pip3 install pymysql 基本使用 from pymysql import connect # 1.创建链接 coon = connect() """ * 参数host:连接...
    99+
    2015-07-26
    在Python中使用MySQL-
  • 在Python中使用QuantLib
    Quantlib简介 相比TA-Lib在技术分析领域的地位,QuantLib在金融工程领域的地位可以说有过之而无不及。 参考其官方网站,QuantLib中包含的的模块如下(其中个人感觉国内比较有用的添加了中文注释): Curre...
    99+
    2023-01-31
    Python QuantLib
  • 在Python中使用Elasticsea
    在这篇文章中,我将讨论Elasticsearch以及如何将其整合到不同的Python应用程序中。什么是ElasticSearch?ElasticSearch(ES)是一个建立在Apache Lucene之上的高度可用的分布式开源搜索引...
    99+
    2023-01-31
    Python Elasticsea
  • Mongodb中使用B树索引的原因是什么
    这篇文章给大家介绍Mongodb中使用B树索引的原因是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。  B树和B+树  开头,我们先回忆一下,B树和B+树的结构以及特点。  树内的...
    99+
    2022-10-18
  • 教你如何使用Python下载B站视频的详细教程
    前言 众所周知,网页版的B站无法下载视频,然本人喜欢经常在B站学习,奈何没有网时,无法观看视频资源,手机下载后屏幕太小又不想看,遂写此程序以解决此问题 步骤 话不多说,进入正题 1....
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作