Python 比较
描述 Python 如何比较对象。
由于 proto 数据的序列化方式,您不能依赖 proto 消息实例的有线表示 (wire representation) 来确定其内容是否与另一个实例相同。有线格式的 proto 消息实例可能变化的方式包括但不限于以下几种:
- protobuf schema 以某些方式发生变化。
- map 字段以不同的顺序存储其值。
- 二进制文件使用不同的标志(例如 opt vs. debug)构建。
- protobuf 库已更新。
由于序列化数据可能以这些方式变化,确定相等性需要使用其他方法。
比较方法
您可以使用标准的 Python ==
运算符来比较 protocol buffer 消息是否相等。使用 ==
运算符比较两个对象时,会与 message.ListFields()
进行比较。在测试时,您可以使用 self.assertEqual(msg1, msg2)
。
如果两个消息具有相同的类型且它们所有对应的字段都相等,则认为它们相等。不等运算符 !=
与 ==
完全相反。
消息的相等性是递归的:要使两个消息相等,任何嵌套的消息也必须相等。
字段相等性和存在性
字段的相等性检查是基于值的。对于具有显式存在性的字段,字段的存在性也会被考虑在内。
一个被显式设置为其默认值的字段与一个未设置的字段被视为不相等。
例如,考虑以下具有显式存在性字段的消息:
edition = "2023";
message MyMessage {
int32 value = 1; // 'explicit' presence by default in Editions
}
如果您创建两个实例,一个实例中 value
未设置,另一个实例中 value
被显式设置为 0
,那么它们将不相等:
msg1 = MyMessage()
msg2 = MyMessage()
msg2.value = 0
assert not msg1.HasField("value")
assert msg2.HasField("value")
assert msg1 != msg2
同样的原则也适用于子消息字段:一个未设置的子消息不等于一个存在但为空(子消息类的默认实例)的子消息。
对于具有隐式存在性的字段,由于无法跟踪其存在性,该字段总是通过其值与另一个消息中的对应字段进行比较。
这种将存在性作为相等性检查一部分的行为,与其他一些语言或 protobuf 库处理相等性的方式不同。在那些实现中,未设置的字段和设置为其默认值的字段有时被视为等效(通常是为了有线格式的兼容性)。在 Python 中,==
执行的是更严格的检查。
其他字段类型
- 重复字段:如果元素数量相同且每个对应的元素都相等,则认为它们相等。元素的顺序很重要。
- Map 字段:如果它们具有相同的键值对集合,则认为它们相等。键值对的顺序不重要。
- 浮点字段(
float
和double
):按值进行比较。请注意浮点数比较中常见的注意事项。