昨天看《核心编程》发现了一个鲜为人知的知识点,在Python中的字典比较和列表比较的策略竟然不相同,下面做具体分析。
字典比较原则
例子
1 2 3 4 5 6 7 |
>>> 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中也存在。
1 2 3 4 5 6 |
>>> 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。
1 2 3 4 5 6 |
>>> dict1['port'] = 'tcp' >>> cmp(dict1, dict2) 1 >>> dic2['port'] = 'udp' >>> cmp(dict1,dict2) -1 |
当向两个字典中的仍和一个添加新元素时,这个字典马上会成为大的那个字典,就像例子中的dict1一样。向dict2添加键-值对后,因为两个字典的长度又相等了,会继续比较它们的键和值。
1 2 3 4 5 6 7 8 |
>>> 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 值。
列表比较原则
例子
1 2 3 4 5 6 7 8 9 10 11 12 |
>>> 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如果比较的值相等,那么两个序列的下一个值继续比较,知道不相等的情况出现,或者到达较短的一个序列的末尾。在这种情况下,长的序列被认为是较大的。这就是为什么上面list2元组类型的比较也是用这种算法。
列表比较总结
列表比较的算法按照以下顺序进行:
(1)对两个列表的元组进行比较
(2)如果比较的元素是同类型的,则比较其值,返回结果。
(3)如果两个元素不是同一种类型,则检查他们是否是数字。
1 2 3 |
a.如果是数字,执行必要的数字强制类型转换,然后比较。 b.如果有一方的元素是数字,则另一方的元素“大”(数字是“最小的”)。 c.否则,通过类型名字的字母顺序进行比较。 |
(4)如果有一个列表首先到达末尾,则另一个长一点的列表“大”。
(5)如果我们用尽了两个列表的元素而且所有的元素都是相等的,那么结果就是个平局,就是说返回一个0。
总结
列表(元组)的比较原则:先大小后长短。
字典的比较原则:先长短,再键,再值。
参考来源
《Python核心编程(第二版)》