Protobuf默认与"缺少必填字段"在序列化时

时间:2015-04-08 14:56:22

标签: python protocol-buffers

ProtoBuf消息上的SerializeToString()方法包含必需的字段,这些字段具有默认值,始终抛出EncodeError,指出消息缺少那些必需字段。但是,如果我检查字段的值,则会设置所有默认值。例如:

// mymessage.proto
message MyMessage {
    required int32 val = 1 [default=18];
}

然后在python:

from mymessage_pb2.py import MyMessage
m = MyMessage()
print m.val # Shows m.val == 18
print m.SerializeToString() # EncodeError

另一方面,如果我这样做:

m.val = m.val
print m.SerializeToString() # No Error

很明显,尽管初始化时有默认值,但它只需要触摸每个字段。对我来说,默认的一个主要观点是只需要有人来更新非默认字段(或者他们需要更改的那些字段),所以这个set-it-to-own方法是一个非常令人遗憾的解决方案。

将字段标记为optional不是解决方案,因为根据我们的规范,这些字段是合法要求的。

更新:我尝试合作包括MergeFrom和CopyFrom,但都没有奏效。所以我写了这个:

def ActuallyInit(obj):
    err = []
    obj.IsInitialized(err)
    for field in err:
        attr = obj.__getattribute__(field)
        try:
            obj.__setattr__(field, attr)
        except:
            ActuallyInit(attr)

然后创建一个protobuf对象并将其传递给ActuallyInit,它以递归方式将每个字段设置为自身。这看起来像是一个丑陋的黑客,所以我将问题留在下面。

问题:有没有办法创建ProtoBuf消息实例并且"说服"它每个已经初始化为默认的字段实际上都不是错误吗?

1 个答案:

答案 0 :(得分:7)

这是按预期工作的。 required表示“作者必须明确填写此字段,而不是使用默认值”。如果您想要允许编写者使用其默认值离开该字段的字段,那么您需要optional。这实际上是requiredoptional之间的唯一差异,因此没有理由将required与默认值一起使用。可以说,如果使用默认值定义required字段,Protobuf编译器应该引发错误,但我当时认为没有实现该限制。

(FWIW,required一直被视为a misfeature,已在Protobuf v3中删除。)