python中集合相等的异常行为

时间:2017-04-05 07:57:14

标签: python

当我运行这行代码时,我无法理解为什么两个lists都相同,但是从同一个列表创建的sets不是

class Field(object):
    def __init__(self, fieldnames):
        self.name = fieldnames[0]
        self.alias = frozenset(fieldnames)

    def __eq__(self, other):
        if not isinstance(other, Field):
            return False
        return len(self.alias & other.alias) >= 1

    def __hash__(self):
        return hash(self.name)

    def __str__(self):
        return "{field_name: %s}" % self.name

    def __repr__(self):
        return "<Field: (%s: %r)" %(self.name, self.alias)

In [185]: field_list1 = [["Field 1"], ["Field 2"], ["Field 3"]]

In [186]: field_list2 = [["Field 1"], ["Field 21", "Field 2"], ["Field 3"]]

In [187]: field1 = [Field(f) for f in field_list1]

In [188]: field2 = [Field(f) for f in field_list2]

In [189]: field1 == field2
Out[189]: True

In [190]: set(field1) == set(field2)
Out[190]: False

根据设置的python docs,如果第一组的每个元素都在第二组中,则两个组是相等的,反之亦然。根据这个定义,两个集合应该相等,但我不确定它们为什么不相同。

  

因此我想知道这种行为背后的原因?

2 个答案:

答案 0 :(得分:3)

你在这里进行了不同的比较。

比较两个列表时,第一个列表中的每个元素都会通过GetValue与另一个列表中的等效元素进行比较,后者会调用==方法。虽然你的方法代码很奇怪(为什么不只是eq?),但根据别名属性的相对大小,它会产生真或假。

然而,完全不同的工作。比较是通过哈希进行的,而不是通过相等进行的;并且您已定义了len(self.alias) == len(other.alias)方法,以根据名称返回不同的结果,而不是别名。

答案 1 :(得分:1)

field1 == field2使用== oprerator(通过调用__eq__)执行逐项比较。

set(field1) == set(field2)检查所有元素是否都在两个集合中。集合中的元素由其哈希标识。您可以从名称中计算哈希值。列表中的某些元素具有不同的名称,因此它们是不同的集合元素。

print(field1[1].name)  # 'Field 2'
print(field2[1].name)  # 'Field 21'

总之,列表比较基于__eq__,但设置比较基于__hash__。它们基于Field类中完全不同的计算,因此您得到的结果不同。