pythonic和高性能协议缓冲区实现。

cprotobuf的Python项目详细描述


一个使用cython的最小快速protobuf实现。 基准测试表明它比google官方的expremental cpp-python实现快得多。

我从2013年开始在生产中使用它,只在python2.7中测试过,欢迎对其他python版本的反馈。

基准

$ ./setup.py build_ext --inplace
$ cd benchmark
$ ./bench.sh
encode[google official pure python]:
10 loops, best of 3: 68.8 msec per loop
encode[google official cpp python]:
100 loops, best of 3: 19.4 msec per loop
encode[py-protobuf][cprotobuf]:
100 loops, best of 3: 3.58 msec per loop
decode[google official pure python]:
10 loops, best of 3: 47.5 msec per loop
decode[google official cpp python]:
100 loops, best of 3: 4.55 msec per loop
decode[py-protobuf][cprotobuf]:
100 loops, best of 3: 3.98 msec per loop

教程

使用插件

你这样写一个person.proto文件:

packagefoo;messagePerson{requiredint32id=1;requiredstringname=2;optionalstringemail=3;}

还有一个people.proto这样的文件:

packagefoo;import"person.proto";messagePeople{repeatedPersonpeople=1;}

然后使用提供的插件编译它:

$ protoc --cprotobuf_out=. person.proto people.proto

如果在windows上运行protobuf插件有困难,可以直接运行protoc-gen-cprotobuf,如下所示:

$ protoc -ofoo.pb person.proto people.proto
$ protoc-gen-cprotobuf foo.pb -d .

然后得到一个python模块foo_pb.py,cprotobuf为每个包而不是每个协议文件生成一个python模块。

生成的代码非常可读:

# coding: utf-8fromcprotobufimportProtoEntity,Field# file: person.protoclassPerson(ProtoEntity):id=Field('int32',1)name=Field('string',2)email=Field('string',3,required=False)# file: people.protoclassPeople(ProtoEntity):people=Field(Person,1,repeated=True)

实际上,如果只使用python,可以编写这个python模块,避免代码生成。

api

现在,您有了这个可爱的python模块,如何解析和序列化消息?

在设计这个包时,我们尽量减少迁移的工作量,因此我们将api的名称与协议缓冲区的名称保持相似。

注意

因为这不需要重用消息实例并在python中对其调用Clear,所以它不提供Clearapi, 所以ParseFromString更像是官方实现中的MergeFromString,因为它一开始不会调用Clear

编码/解码
>>>fromfoo_pbimportPerson,People>>>msg=People()>>>msg.people.add(...id=1,...name='jim',...email='jim@gmail.com',...)>>>s=msg.SerializeToString()>>>msg2=People()>>>msg2.ParseFromString(s)>>>len(msg2)1>>>msg2.people[0].name'jim'

反射

>>>fromfoo_pbimportPerson,People>>>dir(Person._fields[0])['__class__','__delattr__','__doc__','__format__','__get__','__getattribute__','__hash__','__init__','__new__','__pyx_vtable__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','index','name','packed','repeated','required','wire_type']>>>Person._fields[0].name'email'>>>Person._fieldsmap{1:<cprotobuf.Fieldobjectat0xb74a538c>,2:<cprotobuf.Fieldobjectat0xb74a541c>,3:<cprotobuf.Fieldobjectat0xb74a5c8c>}>>>Person._fieldsmap_by_name{'email':<cprotobuf.Fieldobjectat0xb74a5c8c>,'name':<cprotobuf.Fieldobjectat0xb74a541c>,'id':<cprotobuf.Fieldobjectat0xb74a538c>}

重复容器

我们使用RepeatedContainer来表示重复字段,RepeatedContainer是从list继承的,因此您可以像list那样对其进行操作,或者像google的实现那样使用api。

>>>fromfoo_pbimportPerson,People>>>msg=People()>>>msg.people.add(...id=1,...name='jim',...email='jim@gmail.com',...)>>>p=msg.people.add()>>>p.id=2>>>p.name='jake'>>>p.email='jake@gmail.com'>>>p2=Person(id=3,name='lucy',email='lucy@gmail.com')>>>msg.people.append(p2)>>>msg.people.append({...'id':4,...'name':'lily',...'email':'lily@gmail.com',...})

快速编码原始数据

如果您已经将消息表示为listdict,则可以对其进行编码,而无需构造中间对象,从而获得大量开销:

>>>fromcprotobufimportencode_data>>>fromfoo_pbimportPerson,People>>>s=encode_data(People,[...{'id':1,'name':'tom','email':'tom@gmail.com'}...])>>>msg=People()>>>msg.ParseFromString(s)>>>msg.people[0].name'tom'

运行测试

$ nosetests

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java使用(BluetoothGattCharacteristic)特性中的数据创建、写入和保存csv文件。getValue()   java如何使用groupBy创建一个值为BigDecimal字段平均值的映射?   日期时间Java将iso_即时格式的字符串转换为日期   java如何检索和显示Android firebase的配置文件?   scala AWSJAVASDK:解压缩大小必须小于262144000字节   要应用于列表的java JSTL if条件   java在3个点之间画一个正方形   Kotlin java抽象类IllegaAccessError   java原语双值相等取决于大小?   java有没有一种方法可以对数据集使用compareTo()方法,而不必遍历数据集的每个元素?   java为什么我发送的每个UDP消息都会改变端口源?   重新选择文件时swing Java JTree冻结   java不知道我的游戏是怎么回事   Motif L&F中自定义组合框渲染器中的Java Swing消失文本   java Trade Me API访问前的OAuth