Python 比较

描述 Python 如何比较对象。

由于 proto 数据的序列化方式,您不能依赖 proto 消息实例的线表示来确定其内容是否与另一个实例相同。线格式 proto 消息实例可能变化的几种方式包括以下:

  • protobuf 模式以某些方式发生变化。
  • map 字段以不同的顺序存储其值。
  • 二进制文件使用不同的标志构建(例如优化版与调试版)。
  • 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 中,== 执行更严格的检查。

其他字段类型

  • 如果重复字段具有相同数量的元素且每个相应元素相等,则它们相等。元素的顺序很重要。
  • 如果映射字段具有相同的键值对集合,则它们相等。键值对的顺序无关紧要。
  • 浮点字段floatdouble)按值比较。请注意浮点比较的常见注意事项。