将集合转换为列表时会发生什么?
以下单元测试在运行时失败(使用 pytest),但是当我调试它时,它通过了:
def test():
assert list(set(['B', 'A'])) == ['A', 'B']
我知道集合没有 order,但我不明白如何确定list(s) ifs是一个集合的结果,这在编写单元测试时至关重要。这里提到的解决方法是将代码更改为sorted(s),但我想了解list(s)运行时会发生什么。
回答
list(s)只是set以任何顺序迭代set产生其输出。问题是set顺序仅在给定的 Python 运行中是可重复的,并且仅当set以完全相同的方式构造时,因为:
- CPython(以及其他可能的)使用带有虚拟条目的基于开放寻址的哈希表,迭代只是按顺序扫描整个表中的条目;如果您
set以不同的方式构建,即使在相同的过程中,以不同顺序发生的碰撞哈希码会产生不同的顺序(第一个抓住桶的人保留它,下一个被转移到可能与原始位置相去甚远的不同位置桶)。 - 字符串或类似字节的数据(以及一些深奥的东西,如
datetime对象)使用每个进程的种子对哈希进行加密扰动,因此在Python 的不同运行中,完全相同的set构造方式可能具有完全不同的顺序。
简而言之,如果你想检查是否set相等,你有三个选择:
-
将数据保留为
set,例如:def test(): assert set(['B', 'A']) == {'A', 'B'}不关心订单,或者
-
(CPython/PyPy 3.6,任何 Python 3.7+)使用 a
dict模拟 aset但保证插入顺序,例如:assert list(dict.fromkeys(['B', 'A'])) == ['B', 'A'] # Passes assert list(dict.fromkeys(['B', 'A'])) == ['A', 'B'] # Fails在较旧的 Python 上,
collections.OrderedDict可用于获得有保证的排序,尽管它更慢且更需要内存。甚至与插入顺序不同dict,OrderedDict's==是顺序敏感的,因此您可以直接比较OrderedDicts 而不是转换回 slist如果需要,同时仍然需要特定的键排序。 -
对于类型总排序,使用
sorted作为中提到你的链接的答案得到预知的顺序