6.10.1. 值比较

运算符 <, >, ==, >=, <=!= 将比较两个对象的值。 两个对象不要求为相同类型。

对象、值与类型 一章已说明对象都有相应的值(还有类型和标识号)。 对象值在 Python 中是一个相当抽象的概念:例如,对象值并没有一个规范的访问方法。 而且,对象值并不要求具有特定的构建方式,例如由其全部数据属性组成等。 比较运算符实现了一个特定的对象值概念。 人们可以认为这是通过实现对象比较间接地定义了对象值。

由于所有类型都是 object 的(直接或间接)子类型,它们都从 object 继承了默认的比较行为。 类型可以通过实现 丰富比较方法 例如 __lt__() 来定义自己的比较行为,详情参见 基本定制

默认的一致性比较 (==!=) 是基于对象的标识号。 因此,具有相同标识号的实例一致性比较结果为相等,具有不同标识号的实例一致性比较结果为不等。 规定这种默认行为的动机是希望所有对象都应该是自反射的 (即 x is y 就意味着 x == y)。

次序比较 (<, >, <=>=) 默认没有提供;如果尝试比较会引发 TypeError。 规定这种默认行为的原因是缺少与一致性比较类似的固定值。

按照默认的一致性比较行为,具有不同标识号的实例总是不相等,这可能不适合某些对象值需要有合理定义并有基于值的一致性的类型。 这样的类型需要定制自己的比较行为,实际上,许多内置类型都是这样做的。

以下列表描述了最主要内置类型的比较行为。

  • 内置数值类型 (数字类型 —- int, float, complex) 以及标准库类型 fractions.Fractiondecimal.Decimal 可进行类型内部和跨类型的比较,例外限制是复数不支持次序比较。 在类型相关的限制以内,它们会按数学(算法)规则正确进行比较且不会有精度损失。

    非数字值 float('NaN')decimal.Decimal('NaN') 属于特例。 任何数字与非数字值的排序比较均返回假值。 还有一个反直觉的结果是非数字值不等于其自身。 举例来说,如果 x = float('NaN')3 < x, x < 3x == x 均为假值,而 x != x 则为真值。 此行为是遵循 IEEE 754 标准的。

  • NoneNotImplemented 都是单例对象。 PEP 8 建议单例对象的比较应当总是通过 isis not 而不是等于运算符来进行。

  • 二进制码序列 (bytesbytearray 的实例) 可进行类型内部和跨类型的比较。 它们使用其元素的数字值按字典顺序进行比较。

  • 字符串 (str 的实例) 使用其字符的 Unicode 码位数字值 (内置函数 ord() 的结果) 按字典顺序进行比较。 3

    字符串和二进制码序列不能直接比较。

  • 序列 (tuple, listrange 的实例) 只可进行类型内部的比较,range 还有一个限制是不支持次序比较。 以上对象的跨类型一致性比较结果将是不相等,跨类型次序比较将引发 TypeError

    序列比较是按字典序对相应元素进行逐个比较。 内置容器通常设定同一对象与其自身是相等的。 这使得它们能跳过同一对象的相等性检测以提升运行效率并保持它们的内部不变性。

    内置多项集间的字典序比较规则如下:

    • 两个多项集若要相等,它们必须为相同类型、相同长度,并且每对相应的元素都必须相等(例如,[1,2] == (1,2) 为假值,因为类型不同)。

    • 对于支持次序比较的多项集,排序与其第一个不相等元素的排序相同(例如 [1,2,x] <= [1,2,y] 的值与``x <= y`` 相同)。 如果对应元素不存在,较短的多项集排序在前(例如 [1,2] < [1,2,3] 为真值)。

  • 两个映射 (dict 的实例) 若要相等,必须当且仅当它们具有相同的 (键, 值) 对。 键和值的一致性比较强制规定自反射性。

    次序比较 (<, >, <=>=) 将引发 TypeError

  • 集合 (setfrozenset 的实例) 可进行类型内部和跨类型的比较。

    它们将比较运算符定义为子集和超集检测。 这类关系没有定义完全排序(例如 {1,2}{2,3} 两个集合不相等,即不为彼此的子集,也不为彼此的超集。 相应地,集合不适宜作为依赖于完全排序的函数的参数(例如如果给出一个集合列表作为 min(), max()sorted() 的输入将产生未定义的结果)。

    集合的比较强制规定其元素的自反射性。

  • 大多数其他内置类型没有实现比较方法,因此它们会继承默认的比较行为。

在可能的情况下,用户定义类在定制其比较行为时应当遵循一些一致性规则:

  • 相等比较应该是自反射的。 换句话说,相同的对象比较时应该相等:

    x is y 意味着 x == y

  • 比较应该是对称的。 换句话说,下列表达式应该有相同的结果:

    x == yy == x

    x != yy != x

    x < yy > x

    x <= yy >= x

  • 比较应该是可传递的。 下列(简要的)例子显示了这一点:

    x > y and y > z 意味着 x > z

    x < y and y <= z 意味着 x < z

  • 反向比较应该导致布尔值取反。 换句话说,下列表达式应该有相同的结果:

    x == ynot x != y

    x < ynot x >= y (对于完全排序)

    x > ynot x <= y (对于完全排序)

    最后两个表达式适用于完全排序的多项集(即序列而非集合或映射)。 另请参阅 total_ordering() 装饰器。

  • hash() 的结果应该与是否相等一致。 相等的对象应该或者具有相同的哈希值,或者标记为不可哈希。

Python 并不强制要求这些一致性规则。 实际上,非数字值就是一个不遵循这些规则的例子。