为什么 python 集合 "sorted" 是升序的?

Why are python sets "sorted" in ascending order?

让我们运行下面的代码:

st = {3, 1, 2}
st
>>> {1, 2, 3}
st.pop()
>>> 1
st.pop()
>>> 2
st.pop()
>>> 3

虽然据说集合是无序的,但这个集合的行为就像按升序排序一样。根据文档,方法 pop() 应该 return 和 'arbitrary element',returns 元素也按升序排列。这是什么原因?

顺序与对象的哈希值、集合的大小、数字的二进制表示、插入顺序和其他实现参数相关。它是完全任意的,不应该被依赖:

>>> st = {3, 1, 2,4,9,124124,124124124124,123,12,41,15,}
>>> st
{1, 2, 3, 4, 9, 41, 12, 15, 124124, 123, 124124124124}
>>> st.pop()
1
>>> st.pop()
2
>>> st.pop()
3
>>> st.pop()
4
>>> st.pop()
9
>>> st.pop()
41
>>> st.pop()
12
>>> {1, 41, 12}
{1, 12, 41}
>>> {1, 9, 41, 12}
{1, 12, 9, 41}  # Looks like 9 wants to go after 12.
>>> hash(9)
9
>>> hash(12)
12
>>> hash(41)
41
>>> {1, 2, 3, 4, 9, 41, 12}
{1, 2, 3, 4, 9, 12, 41}  # 12 before 41
>>> {1, 2, 3, 4, 9, 41, 12, 15}  # add 15 at the end
{1, 2, 3, 4, 9, 41, 12, 15}  # 12 after 41

您永远不应该依赖集合的顺序。一旦将多个事物放入集合中,就永远无法依赖元素之间的稳定排序。那是Python需要你遵守的契约。

实施细节可能会向您展示一些行为,这些行为可能会让您相信您有时可以预测集合的顺序。例如,正如您所发现的,如果将一些 low-order 降序整数放入一个集合中并打印该集合,它们将按升序显示。这可能是因为一个整数的散列等于它自己。

hash(1) == 1
hash(2) == 2

(你可以制作一个Python程序来确认这一点)。

set 的一个实现细节是它在内部使用散列和桶存储策略——与 Python 的 dict 相同。它的一个实现细节是项目在一个松散地基于散列码如何在内部分区的排序中被遍历。因此对于 Python 的某些实现,例如CPython,你有时会看到整数的确定性排序顺序,因为整数的散列与整数本身紧密绑定(它们是相同的值),这与实现细节相互作用哈希遍历.

set 的合同告诉您永远不要依赖此行为来实现 future-proofing 和 cross-Python 解释器兼容性。

另一个实现细节是 .pop set 将(对于 Python 的某些实现)return 集合中的元素按照您看到元素的顺序排列。因此,如果您打印一个集合以查看其内容,然后从该集合中弹出所有元素,它们将以与您打印该集合时看到的顺序一致的顺序弹​​出。

作为一个实现细节,只要集合的内容没有改变,集合的顺序就是“稳定的”。你不应该依赖这个。允许弹出 select 集合中的任意元素,但不是必需的。