我最近从 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']
…?
最佳答案
更新:在 Python 3.6 中,dict
有一个 new implementation保留插入顺序。从 Python 3.7 开始,这种保持顺序的行为是 guaranteed :
the insertion-order preservation nature of dict objects has been declared to be an official part of the Python language spec.
这是 security fix 的结果从 2012 年开始,为 enabled by default在 Python 3.3 中(向下滚动到“安全改进”)。
来自公告:
Hash randomization causes the iteration order of dicts and sets to be unpredictable and differ across Python runs. Python has never guaranteed iteration order of keys in a dict or set, and applications are advised to never rely on it. Historically, dict iteration order has not changed very often across releases and has always remained consistent between successive executions of Python. Thus, some existing applications may be relying on dict or set ordering. Because of this and the fact that many Python applications which don't accept untrusted input are not vulnerable to this attack, in all stable Python releases mentioned here, HASH RANDOMIZATION IS DISABLED BY DEFAULT.
如上所述,最后一个大写的位在 Python 3.3 中不再适用。
另见: object.__hash__()
documentation (“注意”侧边栏)。
如果绝对必要,您可以通过设置 PYTHONHASHSEED
来禁用受此行为影响的 Python 版本中的哈希随机化。环境变量到 0
.
你的反例:
list({str(i): i for i in range(10)}.keys())
... not 实际上在 Python 3.3 中总是给出相同的结果,尽管不同排序的数量是有限的due to哈希冲突的处理方式:
$ 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 - 为什么字典排序是不确定的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14956313/