python - 为什么 Python list() 并不总是具有相同的顺序?

标签 python

我正在使用 Python 3.5 及其文档,位于 https://docs.python.org/3.5/library/stdtypes.html#sequence-types-list-tuple-range 说:

list([iterable])

(...)

The constructor builds a list whose items are the same and in the same order as iterable’s items. 

好的,对于以下脚本:

#!/usr/bin/python3

import random

def rand6():
    return random.randrange(63) 


random.seed(0)
check_dict = {}

check_dict[rand6()] = 1
check_dict[rand6()] = 1
check_dict[rand6()] = 1

print(list(check_dict))

我总是得到

[24, 48, 54]

但是,如果我将函数更改为:

def rand6():
    return bytes([random.randrange(63)])

那么返回的顺序并不总是相同的:

>./foobar.py
[b'\x18', b'6', b'0']
>./foobar.py
[b'6', b'0', b'\x18']

为什么?

最佳答案

Python 字典是作为哈希表实现的。在大多数 Python 版本中(稍后详细介绍),迭代字典时获取键的顺序是表中值的任意顺序,这与它们的添加顺序关系不大(当发生哈希冲突时,插入的顺序可能会有点影响)。该顺序取决于实现。 Python 语言不提供任何关于顺序的保证,只是如果中间没有添加或删除键,则在字典的多次迭代中它将保持不变。

对于带有整数键的字典,哈希表不会做任何花哨的事情。整数对自身进行哈希处理(-1 除外),因此将相同的数字放入字典中,您将在哈希表中获得一致的顺序。

但是,对于具有 bytes 键的字典,由于哈希随机化,您会看到不同的行为。为了防止一种字典冲突攻击(其中用 Python 实现的 Web 应用程序可以通过向其发送具有数千个 key 的数据来进行攻击,这些 key 哈希为相同的值,从而导致大量冲突并且非常糟糕(O(N**2 ))性能),Python 每次启动时都会选择一个随机种子,并使用它来随机化 Unicode 和字节字符串以及 datetime 类型的哈希函数。

您可以通过将环境变量 PYTHONHASHSEED 设置为 0 来禁用哈希随机化(或者您可以通过将其设置为最大 的任何正整数来选择自己的种子) >2**32-1)。

值得注意的是,这种行为在 Python 3.6 中发生了变化。哈希随机化仍然发生,但字典的迭代顺序不再基于键的哈希值。虽然官方语言政策仍然是顺序是任意的,但 CPython 中 dict 的实现现在保留了其值添加的顺序。在使用常规 dict 时,您不应该依赖此行为,因为开发人员有可能(尽管目前看来不太可能)认为这是一个错误并再次更改实现。如果您想保证迭代按特定顺序发生,请使用collections.OrderedDict类而不是普通的dict

关于python - 为什么 Python list() 并不总是具有相同的顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47008930/

相关文章:

python - 验证 IP 字符串大于或小于 python 中的另一个 IP 字符串

python - Pandas:反转具有相同值的行

python - 在 matplotlib 中设置轴限制,但在其中自动缩放

python - 使用 python chisquare 和使用卡方值表的不同结果

python mysql连接错误时自动连接

python - 如何将两个字符串转换为 Python 中的函数名称

python - 在 python 中执行无操作的标准方法是什么?

python - 调用成员函数的类实例 : C++ Vs Python syntax

python - 从 AWS 运行 FFmpeg

python - Django如何发送GET请求