将集合转换为列表时会发生什么?

以下单元测试在运行时失败(使用 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完全相同的方式构造时,因为:

  1. CPython(以及其他可能的)使用带有虚拟条目的基于开放寻址的哈希表,迭代只是按顺序扫描整个表中的条目;如果您set以不同的方式构建,即使在相同的过程中,以不同顺序发生的碰撞哈希码会产生不同的顺序(第一个抓住桶的人保留它,下一个被转移到可能与原始位置相去甚远的不同位置桶)。
  2. 字符串或类似字节的数据(以及一些深奥的东西,如datetime对象)使用每个进程的种子对哈希进行加密扰动,因此在Python 的不同运行中,完全相同的set构造方式可能具有完全不同的顺序。

简而言之,如果你想检查是否set相等,你有三个选择:

  1. 将数据保留为set,例如:

    def test():
        assert set(['B', 'A']) == {'A', 'B'}
    

    不关心订单,或者

  2. (CPython/PyPy 3.6,任何 Python 3.7+)使用 adict模拟 aset但保证插入顺序,例如:

    assert list(dict.fromkeys(['B', 'A'])) == ['B', 'A']  # Passes
    assert list(dict.fromkeys(['B', 'A'])) == ['A', 'B']  # Fails
    

    在较旧的 Python 上,collections.OrderedDict可用于获得有保证的排序,尽管它更慢且更需要内存。甚至与插入顺序不同dictOrderedDict's==是顺序敏感的,因此您可以直接比较OrderedDicts 而不是转换回 slist如果需要,同时仍然需要特定的键排序。

  3. 对于类型总排序,使用sorted作为中提到你的链接的答案得到预知的顺序


以上是将集合转换为列表时会发生什么?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>