我知道Python字典是无序的,但为什么我总是得到相同顺序的键?
我有一个叫做 tmp
的字典:
>>> tmp
{1: 'ONE', 2: 'TWO', 3: 'THREE'}
>>> type(tmp)
<type 'dict'>
我对这个字典进行了二十次循环,每次循环得到的键的顺序都是一样的。
>>> for i in range(20):
... print tmp.keys()
...
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
我知道在 Python 中,字典是无序的,但是为什么我每次得到的键的顺序总是一样呢?
4 个回答
因为Python的字典是用哈希表来实现的,所以键的顺序是根据它的哈希值来决定的,哈希值决定了存储“键/值”对的位置。
如果用整数作为键,那么哈希值就是这个整数本身。
>>> map(hash, [1,2,3])
[1,2,3]
在这里,你使用的键是连续的整数,它们的哈希值也是连续的,这样底层的哈希算法很可能会选择连续的位置来存储“键/值”对,所以你看到的顺序和你创建字典时的顺序是一样的。这里有一个简单的反例:
>>> tmp = {1:1, 5:5, 10:10}
>>> tmp.keys()
[1, 10, 5]
当然,在循环过程中,你不要修改字典,这样就不会导致哈希表的大小改变,所以顺序就保持不变。
>>> for i in range(5):
... print tmp.keys()
[1, 10, 5]
[1, 10, 5]
[1, 10, 5]
[1, 10, 5]
[1, 10, 5]
如果你对Python的具体实现感兴趣,可以看看这篇不错的文章: Python字典实现
在创建一个字典时,Python会自己决定一个顺序。每次你调用 .keys()
、.values()
或 .items()
时,只要你没有修改这个字典,得到的结果顺序都会是一样的。希望这样说能让你明白。
如下面的例子所示,尽管我创建字典时是按照特定的顺序,但Python会重新排列这个字典。不过,之后只要你不修改字典,顺序就会一直保持不变。
a = {'apple' : 'fruit', 'car' : 'vehicle', 'onion' : 'vegetable'}
print a
for i in range(5):
print a.keys()
[OUTPUT]
{'car': 'vehicle', 'apple': 'fruit', 'onion': 'vegetable'}
['car', 'apple', 'onion']
['car', 'apple', 'onion']
['car', 'apple', 'onion']
['car', 'apple', 'onion']
['car', 'apple', 'onion']
因为如果不这样做,这个就不管用了:
for key, value in zip(d.keys(), d.values()):
...
还有其他类似的问题。
在Python中,字典(dict)和集合(set)的遍历顺序是有保证的,只要这些字典或集合没有被修改。你可以试着往tmp
里添加其他值,下一次你可能会发现顺序变了。
(不过,要注意用小整数作为键并不是一个特别好的例子,因为在CPython中,小整数会直接映射到它们自己,所以它们更有可能按数字顺序出现。你可以试试用一些字符串。)
在你调用 tmp.keys()
之间,你并没有修改 tmp
,所以键的顺序始终不会改变。
如果在调用
items()
、keys()
、values()
、iteritems()
、iterkeys()
和itervalues()
这些方法时,没有对字典进行任何修改,那么返回的列表会直接对应。这意味着你可以使用zip()
来创建(值, 键)
的配对,比如pairs = zip(d.values(), d.keys())
。对于iterkeys()
和itervalues()
方法也是一样的关系:pairs = zip(d.itervalues(), d.iterkeys())
也会提供相同的配对值。另一种创建相同列表的方法是pairs = [(v, k) for (k, v) in d.iteritems()]
。