更新:在 Python 3.6 中,dict
有一个保留插入顺序的新实现。从 Python 3.7 开始,这种保持顺序的行为得到保证:
dict对象的插入顺序保存特性已被宣布为 Python 语言规范的官方部分。
这是2012 年安全修复的结果,在 Python 3.3 中默认启用(向下滚动到“安全改进”)。
来自公告:
哈希随机化导致 dicts 和 set 的迭代顺序是不可预测的,并且在 Python 运行中会有所不同。Python 从未保证 dict 或 set 中键的迭代顺序,建议应用程序永远不要依赖它。从历史上看,dict 迭代顺序在不同版本之间并没有经常改变,并且在 Python 的连续执行之间始终保持一致。因此,一些现有的应用程序可能依赖于 dict 或 set 排序。由于这一点以及许多不接受不受信任输入的 Python 应用程序不易受到这种攻击的事实,在此处提到的所有稳定 Python 版本中,哈希随机化默认禁用。
如上所述,最后一个大写的位在 Python 3.3 中不再适用。
另请参阅: object.__hash__()
文档(“注意”侧边栏)。
如果绝对必要,您可以通过将PYTHONHASHSEED
环境变量设置为0
.
你的反例:
list({str(i): i for i in range(10)}.keys())
…实际上在 Python 3.3 中并不总是给出相同的结果,尽管由于哈希冲突的处理方式不同排序的数量是有限的:
$ for x in {0..999}
> do
> python3.3 -c "print(list({str(i): i for i in range(10)}.keys()))"
> done | sort | uniq -c
61 ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
73 ['1', '0', '3', '2', '5', '4', '7', '6', '9', '8']
62 ['2', '3', '0', '1', '6', '7', '4', '5', '8', '9']
59 ['3', '2', '1', '0', '7', '6', '5', '4', '9', '8']
58 ['4', '5', '6', '7', '0', '1', '2', '3', '8', '9']
55 ['5', '4', '7', '6', '1', '0', '3', '2', '9', '8']
62 ['6', '7', '4', '5', '2', '3', '0', '1', '8', '9']
63 ['7', '6', '5', '4', '3', '2', '1', '0', '9', '8']
60 ['8', '9', '0', '1', '2', '3', '4', '5', '6', '7']
66 ['8', '9', '2', '3', '0', '1', '6', '7', '4', '5']
65 ['8', '9', '4', '5', '6', '7', '0', '1', '2', '3']
53 ['8', '9', '6', '7', '4', '5', '2', '3', '0', '1']
62 ['9', '8', '1', '0', '3', '2', '5', '4', '7', '6']
52 ['9', '8', '3', '2', '1', '0', '7', '6', '5', '4']
73 ['9', '8', '5', '4', '7', '6', '1', '0', '3', '2']
76 ['9', '8', '7', '6', '5', '4', '3', '2', '1', '0']
如本答案开头所述,Python 3.6 不再是这种情况:
$ for x in {0..999}
> do
> python3.6 -c "print(list({str(i): i for i in range(10)}.keys()))"
> done | sort | uniq -c
1000 ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']