为什么由不同初始化集合构造的元组相等?

时间:2014-09-30 08:06:35

标签: python set comparison tuples hashtable

我期待以下两个元组

>>> x = tuple(set([1, "a", "b", "c", "z", "f"]))
>>> y = tuple(set(["a", "b", "c", "z", "f", 1]))

比较不平等,但他们没有:

>>> x == y
>>> True

为什么?

4 个答案:

答案 0 :(得分:68)

乍一看,似乎x应始终等于y,因为由相同元素构成的两个集合始终相等:

>>> x = set([1, "a", "b", "c", "z", "f"])
>>> y = set(["a", "b", "c", "z", "f", 1])
>>> x
{1, 'z', 'a', 'b', 'c', 'f'}
>>> y
{1, 'z', 'a', 'b', 'c', 'f'}
>>> x == y
True

然而始终是从两个相等集合构造的元组(或其他有序集合)相等的情况。

事实上,您的比较结果有时为True,有时为False,至少在Python> = 3.3中。测试以下代码:

# compare.py
x = tuple(set([1, "a", "b", "c", "z", "f"]))
y = tuple(set(["a", "b", "c", "z", "f", 1]))
print(x == y)

......一千次:

$ for x in {1..1000}
> do
>   python3.3 compare.py
> done | sort | uniq -c
147 False
853 True

这是因为,自Python 3.3以来,字符串,字节和日期时间的哈希值是security fix的结果随机化。取决于哈希是什么,"碰撞"可能会发生,这意味着订单项存储在基础数组中(因此迭代顺序)取决于插入顺序。

这是来自文档的相关位:

  

安全改进:

     
      
  • 默认情况下会启用哈希随机化。
  •   
     

- https://docs.python.org/3/whatsnew/3.3.html

编辑:由于评论中提及上述True / False比率表面上令人惊讶......

像字典一样,集合被实现为哈希表 - 因此如果发生冲突,表中项目的顺序(以及迭代顺序)将取决于首先添加的项目(不同于在这种情况下xy)和用于散列的种子(自3.3以来不同的Python调用)。由于碰撞在设计上很少见,而且这个问题中的例子都很小,所以这个问题并不像人们最初想象的那样频繁出现。

有关Python的词典和集合实现的详细说明,请参阅The Mighty Dictionary

答案 1 :(得分:13)

这里有两件事情。

  1. 集合是无序的。 set([1, "a", "b", "c", "z", "f"])) == set(["a", "b", "c", "z", "f", 1])

  2. 当您通过tuple构造函数将集合转换为元组时,它基本上遍历集合并添加迭代返回的每个元素。

  3. 元组的构造函数语法是

    tuple(iterable) -> tuple initialized from iterable's items
    

    致电tuple(set([1, "a", "b", "c", "z", "f"]))与致电tuple([i for i in set([1, "a", "b", "c", "z", "f"])])

    相同

    的值
    [i for i in set([1, "a", "b", "c", "z", "f"])]
    

    [i for i in set(["a", "b", "c", "z", "f", 1])]
    

    与在同一组上迭代相同。

    编辑感谢@ZeroPiraeus(查看他的answer)。这不保证。即使对于同一组,迭代的值也不总是相同的。

    元组构造函数不知道构造集的顺序。

答案 2 :(得分:6)

集合未订购,仅由其成员资格定义。

例如,set([1, 2]) == set([2, 1])

如果每个位置的成员相等,则元组是相等的,但是由于集合的元组是从迭代中平均创建的(按递增的顺序),元组最终也是相等的。

答案 3 :(得分:5)

所以你有两个列表 - 它们具有相同的内容,但顺序不同,你将它们转换成集合 - 它们是相同的,因为它们具有相同的内容。

当你将这些集合转换为元组时,它们将以相同的顺序转换,因为它们是相同的集合,因此元组将是相同的。

在Python2.7中也是如此 - 但是从3.3开始,当哈希值随机化时,你将无法保证这一点 - 因为这两个集合虽然内容相同但不会以相同的顺序迭代。