-->

为什么字典顺序不确定性?为什么字典顺序不确定性?(Why is dictionary orderin

2019-05-06 02:19发布

我最近更换在Python 2.7到Python 3.3,看来,虽然在Python 2字典键的顺序是任意的,而是一致的,在Python 3字典的按键与如获得的订货vars()出现不确定性。

如果我运行:

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

...?

Answer 1:


更新:在Python 3.6, dict有一个新的实现它保留插入顺序。 在Python 3.7,这个保序行为保证 :

的插入顺序保存自然的dict对象已被宣布是Python语言规范的正式组成部分。


这是一个结果安全修补程序从2012年,这是默认启用在Python 3.3(向下滚动到“安全性改进”)。

从公告:

哈希随机导致类型的字典的迭代顺序,并设置为不可预知的和不同的不同的Python运行。 Python已经永远保证密钥的迭代顺序在一个字典或设置和应用程序建议从来没有依靠它。 从历史上看,字典迭代顺序并没有跨版本变化非常频繁,始终保持的Python的连续执行之间是一致的。 因此,一些现有的应用程序可能会依赖于字典或设置排序。 由于这一点,事实上,许多不接受不可信输入Python应用程序不容易受到这种攻击,在这里提到的所有稳定的Python版本中,HASH随机化处于关闭状态。

如上所述,最后,资本位不再在Python 3.3属实。

参见: object.__hash__()文件 ( “说明”栏)。

如果绝对必要,可以在受这种行为通过设置的Python版本禁用散列随机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']


Answer 2:

需要注意的是Python的3.7仍然具有不确定性套但是。 类型的字典保留插入顺序,但集不。 集可以表现出相同的随机行为。

python3 -c "print({str(i) for i in range(9)})"

还给出了不同的结果,从一个运行到下一个。



文章来源: Why is dictionary ordering non-deterministic?