为什么我的Protobuf消息(在Python中)忽略零值?

时间:2017-11-19 05:23:42

标签: python protocol-buffers protoc

我一直致力于为项目实施IPC的protobufs。由于某种原因,未设置/序列化设置为0的值。对于上下文,.proto文件包含以下消息:

syntax = "proto3";

enum SetGet {
    SET = 0;
    GET = 1;
}

message State {
    SetGet setget = 1;
    double x = 2;
    double y = 3;
    double depth = 4;
    double yaw = 5;
    double pitch = 6;
    double roll = 7; 
}

我使用protoc将文件编译为Python _pb2文件,然后尝试运行以下测试脚本:

import filename_pb2 as pb

state = pb.State()
state.x = 0
state.y = 0
state.depth = 0
state.yaw = 0
state.pitch = 0
state.roll = 0
state.setget = pb.SET

print("State: {}".format(state))

state2 = pb.State()
state2.ParseFromString(state.SerializeToString())

print("State2: {}".format(state2))

运行时,会打印以下输出:

State: 
State2: 

似乎没有设置任何东西,或零值以某种方式被忽略。 但是,当我将值(x,y,深度等)更改为非零值(例如0.1)时,我得到以下预期结果:

State: x: 0.1
y: 0.1
depth: 0.1
yaw: 0.1
pitch: 0.1
roll: 0.1

State2: x: 0.1
y: 0.1
depth: 0.1
yaw: 0.1
pitch: 0.1
roll: 0.1

即使打印出数字,由于某种原因,枚举仍然不是。 为什么这会发生在protobufs上?默认情况下是double类型0,因此protobuf序列化程序会忽略它们来节省空间吗?那么,为什么在解析State2时它们没有被恢复?我错过了文档中的某些内容吗?提前谢谢!

- 蒂姆

3 个答案:

答案 0 :(得分:7)

是,0是默认值。 the documentation中明确提到了这种情况:

  

请注意,对于标量消息字段,一旦解析了消息,就会出现消息   无法确定某个字段是否已明确设置为默认值   value(例如,布尔值是否设置为false)或者没有设置   根本没有:在定义消息类型时,您应该牢记这一点。   例如,没有布尔值可以在什么时候打开某些行为   如果您不希望这种行为也发生,则设置为false   默认。另请注意,如果标量消息字段设置为其   默认情况下,该值不会在线路上序列化。

答案 1 :(得分:2)

零是protobuf中数字的默认值,空字符串是字符串的默认值。为了提高效率,默认值不会通过线路传输。

如果您真的想知道它是否已明确设置,请不要使用默认零进行实际操作:

enum SetGet {
    NONE = 0;
    SET = 1;
    GET = 2;
}

请记住,这会导致网络上的额外流量,并且由于您只是真的担心打印的是什么,您也可以理解为零是默认值,或者编写输出所有内容的自己的打印例程。

答案 2 :(得分:1)

这最近有所改变; proto3 现在支持通过添加 optional 关键字启用状态跟踪:

message State {
    optional SetGet setget = 1;
    optional double x = 2;
    optional double y = 3;
    optional double depth = 4;
    optional double yaw = 5;
    optional double pitch = 6;
    optional double roll = 7; 
}

来自https://github.com/protocolbuffers/protobuf/blob/master/CHANGES.txt

<块引用>

2021-02-05 版本 3.15.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

协议编译器

  • proto3 的可选字段默认启用,不再需要 --experimental_allow_proto3_optional 标志。

这是它的 RTM:

<块引用>

2020-05-12 版本 3.12.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

协议编译器

  • [实验] 现在支持 proto3 中的单一、非消息类型字段 存在跟踪。这是通过添加“可选”字段标签和 将 --experimental_allow_proto3_optional 标志传递给 protoc。