昨天看《核心编程》发现了一个鲜为人知的知识点,在Python中的字典比较和列表比较的策略竟然不相同,下面做具体分析。

字典比较原则

例子

>>> dict1 = {}
>>> dict2 = {'host':'earth','port':80}
>>> cmp(dict1, dict2)
-1
>>> dict1['host'] = 'earth'
>>> cmp(dict1,dict2)
-1

第一个比较中,dict1比dict2小,因为dict2有更多的元素(2个vs.0个)。在向dict1添加一个元素后,dict1仍然比dict2小(2个vs.1个),虽然添加的元素在dict2中也存在。

>>> dict1['port'] = 8080
>>> cmp(dict1, dict2)
1
>>> dict1['port'] = 80
>>> cmp(dict1, dict2)
0

在向dict1添加第二个元素后,两个字典的长度相同,所以用键比较大小。这时键相等,则通过它们的值比较大小。键'host'的值相同,对于键'port',dict1中值比dict2中的值大(8080 vs. 80)。当把dict2中'port'的值设成和dict1中的值一样,那么两个字典相等:它们有相同的大小、相同的键、相同的值,所以cmp()返回值是0。

>>> dict1['port'] = 'tcp'
>>> cmp(dict1, dict2)
1
>>> dic2['port'] = 'udp'
>>> cmp(dict1,dict2)
-1

当向两个字典中的仍和一个添加新元素时,这个字典马上会成为大的那个字典,就像例子中的dict1一样。向dict2添加键-值对后,因为两个字典的长度又相等了,会继续比较它们的键和值。

>>> cdict = {'fruits':1}
>>> ddict = {'fruits':1}
>>> cmp(cdict,ddict)
0
>>> cdict['oranges'] = 0
>>> ddict['apples'] = 0
>>> cmp(cdict, ddict)
14

上面的例子表明cmp()可以返回除-1、0、1外的其他值。

字典比较总结

字典比较的算法按照以下顺序进行:
(1)比较字典长度
如果字典的长度不同,那么用 cmp(dict1, dict2) 比较大小时,如果字典 dict1 比 dict2 长,cmp()返回正值,如果 dict2 比 dict1 长,则返回负值。也就是说,字典中的键的个数越多,这个字典就越大,即:
len(dict1) > len(dict2) ==> dict1 > dict2
(2)比较字典的键
如果两个字典的长度相同,那就按字典的键比较;键比较的顺序和 keys()方法返回键的顺序相同。 (注意: 相同的键会映射到哈希表的同一位置,这保证了对字典键的检查的一致性。) 这时,如果两个字典的键不匹配时,对这两个(不匹配的键)直接进行比较。当 dict1 中第一个不同的键大于 dict2 中第一个不同的键,cmp()会返回正值。
(3)比较字典的值
如果两个字典的长度相同而且它们的键也完全匹配,则用字典中每个相同的键所对应的值进行比较。一旦出现不匹配的值,就对这两个值进行直接比较。若 dict1 比 dict2 中相同的键所对应的值大,cmp()会返回正值。
(4)完全匹配
到此为止,即,每个字典有相同的长度、相同的键、每个键也对应相同的值,则字典完全匹配,返回 0 值。

列表比较原则

例子

>>> list1,list2 = [123,'xyz'],[456,'abc']
>>> cmp(list1, list2)
-1
>>>
>>> cmp(list2, list1)
1
>>> list3 = list2 + [789]
>>> list3
[456,'abc',789]
>>>
>>> cmp(list2,list3)
-1

当我们比较list1和list2时,list1和list2逐项比较。第一个比较操作发生在两个列表的第一个元素之间,比如说,123与456比较,因为123<456,所以list1被认为小于list2
如果比较的值相等,那么两个序列的下一个值继续比较,知道不相等的情况出现,或者到达较短的一个序列的末尾。在这种情况下,长的序列被认为是较大的。这就是为什么上面list2<list3的原因。
元组类型的比较也是用这种算法。

列表比较总结

列表比较的算法按照以下顺序进行:
(1)对两个列表的元组进行比较
(2)如果比较的元素是同类型的,则比较其值,返回结果。
(3)如果两个元素不是同一种类型,则检查他们是否是数字。

a.如果是数字,执行必要的数字强制类型转换,然后比较。
b.如果有一方的元素是数字,则另一方的元素“大”(数字是“最小的”)。
c.否则,通过类型名字的字母顺序进行比较。

(4)如果有一个列表首先到达末尾,则另一个长一点的列表“大”。
(5)如果我们用尽了两个列表的元素而且所有的元素都是相等的,那么结果就是个平局,就是说返回一个0。

总结

列表(元组)的比较原则:先大小后长短。
字典的比较原则:先长短,再键,再值。

参考来源

《Python核心编程(第二版)》


bingo彬哥
2.5k 声望366 粉丝