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