Python 为什么字典排序是不确定的?

Python 为什么字典排序是不确定的?,python,dictionary,python-3.x,python-3.3,non-deterministic,Python,Dictionary,Python 3.x,Python 3.3,Non Deterministic,我最近从Python2.7切换到Python3.3,在Python2中,字典键的顺序似乎是任意的,但一致的,而在Python3中,使用例如获取的字典键的顺序似乎是不确定的 如果我跑步: class Test(object): pass parameters = vars(Test) print(list(parameters.keys())) 在Python 2.7和Python 3.3中,然后: Python 2.7始终为我提供 ['__dict__', '__module__', '__

我最近从Python2.7切换到Python3.3,在Python2中,字典键的顺序似乎是任意的,但一致的,而在Python3中,使用例如获取的字典键的顺序似乎是不确定的

如果我跑步:

class Test(object): pass
parameters = vars(Test)
print(list(parameters.keys()))
在Python 2.7和Python 3.3中,然后:

  • Python 2.7始终为我提供

    ['__dict__', '__module__', '__weakref__', '__doc__']
    
  • 使用Python 3.3,我可以获得任意随机顺序–例如:

    ['__weakref__', '__module__', '__qualname__', '__doc__', '__dict__']
    ['__doc__', '__dict__', '__qualname__', '__module__', '__weakref__']
    ['__dict__', '__module__', '__qualname__', '__weakref__', '__doc__']
    ['__weakref__', '__doc__', '__qualname__', '__dict__', '__module__']
    
这种非决定论从何而来?为什么会这样

list({str(i): i for i in range(10)}.keys())
…在跑步之间保持一致,始终给予

['3', '2', '1', '0', '7', '6', '5', '4', '9', '8']
…?


更新:在Python3.6中,
dict
具有保留插入顺序的。在Python 3.7中,这种保序行为是:

对象的插入顺序保留性质将成为Python语言规范的正式部分


这是从2012年开始的一个测试的结果,该测试是在Python3.3中进行的(向下滚动到“安全改进”)

从公告中:

散列随机化导致dict和set的迭代顺序为 不可预测且在Python运行中有所不同。Python从未保证 dict或集合中键的迭代顺序,建议应用程序不要 依靠它。从历史上看,dict迭代顺序在不同的应用程序中并没有经常改变 释放,并始终保持连续执行 python因此,一些现有应用程序可能依赖dict或set排序。 由于这一点以及许多Python应用程序不接受 在所有稳定的Python版本中,不受信任的输入不易受到此攻击 这里提到,默认情况下禁用散列随机化

如上所述,最后一个大写位在Python 3.3中不再正确

另请参见:(“注意”侧栏)

如果绝对必要,可以通过将环境变量设置为
0
,在受此行为影响的Python版本中禁用哈希随机化


你的反例是:

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']

请注意,Python 3.7仍然具有非确定性集。DICT保留插入顺序,但集合不保留。集合可以显示相同的随机行为

python3-c“打印({str(i)表示范围(9)中的i})”


从一次运行到下一次运行仍然给出不同的结果。

那么,为什么这不适用于像
{str(i):i for i in range(10)}
?那么我们如何禁用这种随机化呢?@nmz787来这里发布答案,因为我很难找到这个答案。。。然后我看到了这个+1.