说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
比较运算将两个对象或两个对象的值进行比较,返回的是一个布尔值。它们的优先级相同,串联运算时,从左往右依次执行,前面的结果不断与后面的结果比较,除非有圆括号改变它们的优先级。
比较运算共有 8 种比较运算符,它们分别是:
运算 | 说明 |
---|---|
< | 严格小于 |
<= | 小于或等于 |
> | 严格大于 |
>= | 大于或等于 |
== | 等于 |
!= | 不等于 |
is | 是否同一个对象 |
is not | 是否不是同一个对象 |
in | 成员检测,是否是其成员 |
not in | 是否不是其成员 |
这些比较操作可分为三类:
一般情况下,除了几种数字类型之间会按数字大小进行比较外,不同类型的对象不能进行相等比较。字符之间按编码的序号进行比较;元组和列表内部之间按对应值的大小依次
比较;集合和字典由于没有顺序的特性,所以是不能比较的。
如果自定义的类型想实现相等比较操作,需要自己实现对象相应的特殊方法,如 __lt__()
(小于)和 __eq__()
(等于)等。两个包含 is 的对象操作是无法自定义的,因为对比的是对象,任意两个相同或者不同类型的对象都支持。
以下是比较运算的一些示例:
a = 0
b = 1
c = 2
a > b # False
a == b # False
b == (c - b) # True
a != b # True
a < b <= c # True 链式比较
a < (b + c) # True
a is not a # False
a is (b-b) # True
False is None # False
'a' < 'b' # True
'aac' > 'aaa' # True
[1, 2, 3] == [1, 2, 2] # False
[1, 2, 3] > [1, 2] # True
(1, 2, 3) > (2, 3) # False
1 > False # Ture
成员检测:
'a' in 'abc'
# True
'ab' in 'abc'
# True
'ac' in 'abc'
# False
'' in 'abc'
# True
'' in ''
# True
2 in range(4)
# True
4 not in range(4)
# True
'abb' in ['abc', 'efg']
# False
'ac' in ['abc', 'efg']
# False
['abc', 'efg'][0] in ['abc', 'efg']
# True
与 C 不同,Python 中所有比较运算的优先级相同,低于任何算术、移位或位运算。 另一个与 C 不同之处在于 a < b < c 这样的表达式会按传统算术法则来解读:
comparison ::= or_expr (comp_operator or_expr)*
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="
| "is" ["not"] | ["not"] "in"
比较运算会产生布尔值: True 或 False。 自定义的 富比较方法 可能返回非布尔值。 在此情况下 Python 将在布尔运算上下文中对该值调用 bool()。
比较运算可以任意串连,例如 x < y <= z
等价于 x < y and y <= z
,除了 y 只被求值一次(但在两种写法下当 x < y 值为假时 z 都不会被求值)。
正式的说法是这样:如果 a, b, c, ..., y, z
为表达式而 op1, op2, ..., opN
为比较运算符,则 a op1 b op2 c ... y opN z
就等价于 a op1 b and b op2 c and ... y opN z
,不同点在于每个表达式最多只被求值一次。
请注意 a op1 b op2 c 不意味着在 a 和 c 之间进行任何比较,因此,如 x < y > z
这样的写法是完全合法的(虽然也许不太好看)。
运算符 <, >, ==, >=, <= 和 != 将比较两个对象的值。 两个对象不要求为相同类型。
对象、值与类型 一章已说明对象都有相应的值(还有类型和标识号)。 对象值在 Python 中是一个相当抽象的概念:例如,对象值并没有一个规范的访问方法。 而且,对象值并不要求具有特定的构建方式,例如由其全部数据属性组成等。 比较运算符实现了一个特定的对象值概念。 人们可以认为这是通过实现对象比较间接地定义了对象值。
由于所有类型都是 object 的(直接或间接)子类型,它们都从 object 继承了默认的比较行为。 类型可以通过实现 丰富比较方法 例如 lt() 来定义自己的比较行为,详情参见 基本定制。
默认的一致性比较 (== 和 !=) 是基于对象的标识号。 因此,具有相同标识号的实例一致性比较结果为相等,具有不同标识号的实例一致性比较结果为不等。 规定这种默认行为的动机是希望所有对象都应该是自反射的 (即 x is y 就意味着 x == y)。
次序比较 (<, >, <= 和 >=) 默认没有提供;如果尝试比较会引发 TypeError。 规定这种默认行为的原因是缺少与一致性比较类似的固定值。
按照默认的一致性比较行为,具有不同标识号的实例总是不相等,这可能不适合某些对象值需要有合理定义并有基于值的一致性的类型。 这样的类型需要定制自己的比较行为,实际上,许多内置类型都是这样做的。
以下列表描述了最主要内置类型的比较行为。
非数字值 float('NaN') 和 decimal.Decimal('NaN') 属于特例。 任何数字与非数字值的排序比较均返回假值。 还有一个反直觉的结果是非数字值不等于其自身。 举例来说,如果 x = float('NaN') 则 3 < x, x < 3 和 x == x 均为假值,而 x != x 则为真值。 此行为是遵循 IEEE 754 标准的。
None 和 NotImplemented 都是单例对象。 PEP 8 建议单例对象的比较应当总是通过 is 或 is not 而不是等于运算符来进行。
二进制码序列 (bytes 或 bytearray 的实例) 可进行类型内部和跨类型的比较。 它们使用其元素的数字值按字典顺序进行比较。
字符串 (str 的实例) 使用其字符的 Unicode 码位数字值 (内置函数 ord() 的结果) 按字典顺序进行比较。 3
字符串和二进制码序列不能直接比较。
序列比较是按字典序对相应元素进行逐个比较。 内置容器通常设定同一对象与其自身是相等的。 这使得它们能跳过同一对象的相等性检测以提升运行效率并保持它们的内部不变性。
内置多项集间的字典序比较规则如下:
两个多项集若要相等,它们必须为相同类型、相同长度,并且每对相应的元素都必须相等(例如,[1,2] == (1,2) 为假值,因为类型不同)。
对于支持次序比较的多项集,排序与其第一个不相等元素的排序相同(例如 [1,2,x] <= [1,2,y] 的值与 x <= y 相同)。 如果对应元素不存在,较短的多项集排序在前(例如 [1,2] < [1,2,3] 为真值)。
两个映射 (dict 的实例) 若要相等则必须当且仅当它们具有相等的 (key, value) 对。 键和值的相相等性比较强制要求自反射性。
次序比较 (<, >, <= 和 >=) 将引发 TypeError。
集合 (set 或 frozenset 的实例) 可进行类型内部和跨类型的比较。
它们将比较运算符定义为子集和超集检测。 这类关系没有定义完全排序(例如 {1,2} 和 {2,3} 两个集合不相等,即不为彼此的子集,也不为彼此的超集。 相应地,集合不适宜作为依赖于完全排序的函数的参数(例如如果给出一个集合列表作为 min(), max() 和 sorted() 的输入将产生未定义的结果)。
集合的比较强制规定其元素的自反射性。
大多数其他内置类型没有实现比较方法,因此它们会继承默认的比较行为。
在可能的情况下,用户定义类在定制其比较行为时应当遵循一些一致性规则:
相等比较应该是自反射的。 换句话说,相同的对象比较时应该相等:
x is y 意味着 x == y
比较应该是对称的。 换句话说,下列表达式应该有相同的结果:
x == y 和 y == x
x != y 和 y != x
x < y 和 y > x
x <= y 和 y >= x
比较应该是可传递的。 下列(简要的)例子显示了这一点:
x > y and y > z 意味着 x > z
x < y and y <= z 意味着 x < z
反向比较应该导致布尔值取反。 换句话说,下列表达式应该有相同的结果:
x == y 和 not x != y
x < y 和 not x >= y (对于完全排序)
x > y 和 not x <= y (对于完全排序)
最后两个表达式适用于完全排序的多项集(即序列而非集合或映射)。 另请参阅 total_ordering() 装饰器。
hash() 的结果应该与是否相等一致。 相等的对象应该或者具有相同的哈希值,或者标记为不可哈希。
Python 并不强制要求这些一致性规则。 实际上,非数字值就是一个不遵循这些规则的例子。
运算符 in 和 not in 用于成员检测。 如果 x 是 s 的成员则 x in s 求值为 True,否则为 False。 x not in s 返回 x in s 取反后的值。 所有内置序列和集合类型以及字典都支持此运算,对于字典来说 in 检测其是否有给定的键。 对于 list, tuple, set, frozenset, dict 或 collections.deque 这样的容器类型,表达式 x in y 等价于 any(x is e or x == e for e in y)
。
对于字符串和字节串类型来说,当且仅当 x 是 y 的子串时 x in y 为 True。 一个等价的检测是 y.find(x) != -1
。 空字符串总是被视为任何其他字符串的子串,因此 "" in "abc" 将返回 True。
对于定义了 __contains__()
方法的用户自定义类来说,如果 y.__contains__(x)
返回真值则 x in y 返回 True,否则返回 False。
对于未定义 __contains__()
但定义了 __iter__()
的用户自定义类来说,如果在对 y 进行迭代时产生了值 z 使得表达式 x is z or x == z
为真,则 x in y
为 True。 如果在迭代期间引发了异常,则等同于 in 引发了该异常。
最后将会尝试旧式的迭代协议:如果一个类定义了 __getitem__()
,则当且仅当存在非负整数索引号 i 使得 x is y[i] or x == y[i]
并且没有更小的索引号引发 IndexError 异常时 x in y 为 True。 (如果引发了任何其他异常,则等同于 in 引发了该异常)。
运算符 not in 被定义为具有与 in 相反的逻辑值。
运算符 is 和 is not 用于检测对象的标识号:当且仅当 x 和 y 是同一对象时 x is y 为真。 一个对象的标识号可使用 id() 函数来确定。 x is not y 会产生相反的逻辑值。
更新时间:May 5, 2024, 8:53 p.m. 标签:python 比较运算