广告
返回顶部
首页 > 资讯 > 后端开发 > Python >69.Protobuf进阶——使用Pyt
  • 263
分享到

69.Protobuf进阶——使用Pyt

进阶ProtobufPyt 2023-01-31 05:01:42 263人浏览 泡泡鱼

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

摘要

定义addressbookproto 编译Protocol buffer 使用python的Protobuf api 枚举 标准message方法 序列化和解析 将message写入文件 从文件读取message对象 me

  • 定义addressbookproto
  • 编译Protocol buffer
  • 使用python的Protobuf api
    • 枚举
    • 标准message方法
    • 序列化和解析
    • 将message写入文件
    • 从文件读取message对象
  • message的赋值

转载请注明原始链接:Http://blog.csdn.net/a464057216/article/details/54932719

用一个例子说明使用Python操作PB的方法:
1.定义.proto文件。
2.编译.proto文件产出Python代码。
3.使用Python API读写message。
该例子完成一个地址簿程序,能够对地址簿信息进行读写,地址簿中每个人的信息包括姓名、ID、email、联系电话。

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 phones = 4;
}

message AddressBook {
    repeated Person people = 1;
}
protoc --python_out=. addressbook.proto

生成addressbook_pb2.py

在Python脚本中使用addressbook_pb2.py:

import addressbook_pb2 as addressbook

person = addressbook.Person()
person.id = 1234
person.name = "John Doe"
person.email = "jdoe@example.com"
phone = person.phones.add() #phones字段是符合类型,调用add()方法初始化新实例。如果phones字段是标量类型,直接append()添加新元素即可。
phone.number = "555-4321"
phone.type = addressbook.Person.HOME

如果访问.proto文件中未定义的域,抛出AttributeError,如果为某个域赋予了错误类型的值,抛出TypeError。在某个域未赋值前访问该域,返回这个域的默认值。

枚举

有整型值的符号常量,比如addressbook.Person.WORK的值是2。

标准message方法

每个Message类含有一些检查或操作整个message的方法,比如:
• IsInitialized():检查是否所有required域都已赋值。
str():返回message的可读形式,可以通过str(message)或者print message触发,用于调试代码。
• Clear():将所有域的赋值清空。
• MergeFrom(other_msg):将给定的other_msg的内容合并到当前message,独立的域使用other_msg的值覆盖写入,repeated域的内容append到当前message的对应字段。独立的子message和group被递归的合并。
• CopyFrom(other_msg):先对本message调用Clear()方法,再调用MergeFrom(other_msg)。
• MergeFromString(serialized):将PB二进制字符串解析后合并到本message,合并规则与MergeFrom方法一致。
• ListFields():以(Google.protobuf.descriptor.FieldDescriptor,value)的列表形式返回非空的域,独立的域如果HasField返回True则是非空的,repeated域至少包含一个元素则是非空的。
• ClearField(field_name):清空某个域,如果被清空的域名不存在,抛出ValueError异常。
• ByteSize():返回message占用的空间大小。
• WichOneof(oneof_group):返回oneof组中被设置的域的名字或None,如果提供的oneof的组名不存在,抛出ValueError异常。比如test.proto中内容如下:

message Test {
    required string a = 1;
    optional float b = 2;
    oneof l {
        string c = 3;
        int32 d = 4;
        float e = 5;
    }
}

调用WhichOneof的代码如下:

import test_pb2 as test

t1 = test.Test()

t1.a = "t1"
t1.b = 1.0
t1.c = "oneof c"
print t1.WhichOneof('l')

运行输出:

c

序列化和解析

每个Message类都有序列化和解析方法:
• SerializeToString():将message序列化并返回str类型的结果(str类型只是二进制数据的一个容器而已,而不是文本内容)。如果message没有初始化,抛出message.EncodeError异常。
• SerializePartialToString():将message序列化并返回str类型的结果,但是不检查message是否初始化。
• ParseFromString(data):从给定的二进制str解析得到message对象。

如果要在生成的PB类的基础上增加新的功能,应该采用包装(wrapper)的方式,永远不要将PB类作为基类派生子类添加新功能。

将message写入文件

import addressbook_pb2
import sys

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.phones.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 "Unkown phone type; leaving as default value"

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.people.add())

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

从文件读取message对象

import addressbook_pb2
import sys

def ListPeople(address_book):
    for person in address_book.people:
        print "Person ID:", person.id
        print " Name:", person.name
        if person.HasField("email"):
            print " E-mail adress:", person.email

        for phone_number in person.phones:
            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 

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)

如果Message.HasField(field_name)的参数对应的域规则是optional,且该域没有设置值,返回False,如果对应的域规则是repeated,且该域没有设置值,抛出ValueError异常。

message中,标量类型和枚举类型的域,必须通过message.field_name=value的格式赋值,message类型的域,可以使用tmp=message.field_name赋值给tmp后,通过操作tmp赋值。当然,message类型的域也可以使用同标量赋值一样的格式赋值。
比如test.proto内容为:

message Test {
    required inner a = 1;
    message inner {
        required string a = 2;
        optional int32 b =3;
    }
    optional Color b = 4;
    enum Color {
        RED = 0;
        GREEN = 1;
    }
    optional string c = 5;
}

赋值的代码为:

import test_pb2 as test

t1 = test.Test()
t1.c = "Scalar"
a = t1.a
a.a = "message string"
a.b = 1
# 使用如下方式赋值也可以
# t1.a.a = "message string"
# t1.a.b = 1
t1.b = test.Test.RED
print "t1:\n", t1

如果觉得我的文章对您有帮助,欢迎关注我(CSDN:Mars Loo的博客)或者为这篇文章点赞,谢谢!

--结束END--

本文标题: 69.Protobuf进阶——使用Pyt

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

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

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

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

下载Word文档
猜你喜欢
  • 69.Protobuf进阶——使用Pyt
    定义addressbookproto 编译Protocol buffer 使用Python的Protobuf API 枚举 标准message方法 序列化和解析 将message写入文件 从文件读取message对象 me...
    99+
    2023-01-31
    进阶 Protobuf Pyt
  • HTML5进阶FileReader的使用
    FileReader 对象FileReader 对象主要用来把文件读入内存,并且读取文件中的数据。通过构造函数创建一个 FileReader 对象。...
    99+
    2023-06-03
  • Python 3 进阶 —— 使用 P
    PyMySQL 是一个纯 Python 实现的 MySQL 客户端操作库,支持事务、存储过程、批量执行等。 PyMySQL 遵循 Python 数据库 API v2.0 规范,并包含了 pure-Python MySQL 客户端库。 安装...
    99+
    2023-01-31
    进阶 Python
  • C#使用protobuf-net进行序列化的详细操作
    protobuf 是 google的一个开源项目,可用于以下两种用途: (1)数据的存储(序列化和反序列化),类似于xml、json等; (2)制作网络通信协议。   源代码下载地址...
    99+
    2022-11-12
  • 怎样进行SoapUI的进阶使用
    这期内容当中小编将会给大家带来有关怎样进行SoapUI的进阶使用,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。关于SoapUI的简单使用,大家可以参考网上并自己摸索下,这里就不说了,下面说的是一些不常见的...
    99+
    2023-06-17
  • SQL简单使用-进阶篇
    与上一篇的《SQL简单使用-基础篇》相连续的篇章,《SQL简单使用-基础篇》以下简称《基础篇》。在《基础篇》中,主要简单的带大家了解一下SQL命令中最主要的增删改查命令的使用,增INSERT INTO、删D...
    99+
    2022-10-18
  • Swift 进阶 —— map 和 flatMap的使用
    map 和 flatMap 主要分在集合上的使用和在可选类型上的使用,下面分别来看下。 集合上使用 map 和 flatMap 先看如下的代码: func getInfos(by...
    99+
    2022-06-02
    Swift map flatMap
  • Android中的Fragment类使用进阶
    0、回顾 Fragment 代表 Activity 当中的一项操作或一部分用户界面。 一个 Activity 中的多个 Fragment 可以组合在一起,形成一个多部分拼接而成...
    99+
    2022-06-06
    fragment Android
  • Android 玩转Glide4---进阶使用篇
    前言 系列文章专栏: 玩转Glide4 基础使用篇:Android 玩转Glide4—基础使用篇 进阶使用篇:Android 玩转Glide4—...
    99+
    2022-06-06
    glide Android
  • Spring Cloud Alibaba Nacos Config进阶使用
    目录一、SpringBoot 使用 Nacos Config 实现多环境切换1. 现象2. 引入依赖3. 添加bootstrap.yaml配置文件4. 配置对应关系图5. 文件格式简...
    99+
    2022-11-12
  • Oracle进阶DECODE函数使用详解
    DECODE含义 decode(条件,值1,返回值1,值2,返回值2,…值n,返回值n,缺省值) 这个是decode的表达式,具体的含义解释为: IF 条件=值1 THEN   ...
    99+
    2022-11-12
  • Vue3进阶主题CompositionAPI使用详解
    目录什么是Composition API为什么Vue3推荐使用Composition API总结什么是Composition API Composition API 是 Vue3 ...
    99+
    2023-05-15
    Vue3主题Composition API Vue Composition
  • node.js中Socket.IO的进阶使用技巧
    在上一篇博文Socket.IO中,我简要介绍了Socket.IO的基本使用方法并创建了一个简单的聊天室DEMO。本篇在入门篇的基础上,继续探讨Socket.IO的进阶用法。本篇将从配置、房间、事件等方面入手...
    99+
    2022-06-04
    进阶 使用技巧 js
  • Vue 3.0进阶之如何使用VNode
    这篇文章主要讲解了“Vue 3.0进阶之如何使用VNode”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Vue 3.0进阶之如何使用VNode”吧!一、VN...
    99+
    2022-10-19
  • @EnableAsync的使用、进阶、源码分析
    @EnableAsync使用 基础使用 使用@EnableAsync开启异步切面,然后在异步调用的方法上加上@Asyc注解即可 @SpringBootApplication@EnableAsync /...
    99+
    2023-10-24
    java spring
  • 【MySQL】MySQL数据库的进阶使用
    别灰心,一切都会好起来的… 文章目录 一、MySQL基本查询1.对表内容进行Create(增加)1.1 insert语句的使用1.2 插入查询结果(删除表中的重复记录) 2.对表内容进行Retrieve(读取)3.对表内容进...
    99+
    2023-08-17
    数据库 mysql
  • Go gRPC服务进阶middleware使用教程
    目录前言go-grpc-middleware简介grpc_zap日志记录grpc_auth认证grpc_recovery恢复总结前言 之前介绍了gRPC中TLS认证和自定义方法认证,...
    99+
    2022-11-13
  • Vue3进阶主题Composition API如何使用
    这篇文章主要讲解了“Vue3进阶主题Composition API如何使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Vue3进阶主题Composition API如何...
    99+
    2023-07-06
  • vue3Vite进阶rollup命令行使用详解
    目录rollup介绍以命令行方式打包Tree ShakingRollup 的命令行使用命令行format 格式rollup.config.js设置/获取环境变量插件 pluginsr...
    99+
    2022-11-13
  • Loguru基本、进阶使用方法小结。
    loguru简介 loguru是一个开源的Python日志记录器,它提供了简单且易于使用的接口,同时具有高度的可定制性。loguru的特点包括:支持格式化日志、记录到文件或终端、支持自动清理日志、支持...
    99+
    2023-09-14
    linux python pytorch 深度学习
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作