列表和集合的成员测试有什么不同?

9 投票
4 回答
2560 浏览
提问于 2025-04-16 13:14

我在搞清楚为什么第一个判断是正常的,而第二个却报错时遇到了困难。

subject_list = [Subject("A"), Subject("B"), Subject("C")]
subject_set = set()
subject_set.add(Subject("A"))
subject_set.add(Subject("B"))
subject_set.add(Subject("C"))

self.assertIn(Subject("A"), subject_list)
self.assertIn(Subject("A"), subject_set)

这是报错信息:

Traceback (most recent call last):
  File "C:\Users\...\testSubject.py", line 34, in testIn
    self.assertIn(Subject("A"), subject_set)
AssertionError: <Subject: A> not found in set([<Subject: B>, <Subject: C>, <Subject: A>])

在Subject类中,判断两个对象是否相等的方式很简单,就是用 self.name == other.name。在另一个单元测试中,我验证了 Subject("A") == Subject("A") 是成立的。我真的搞不明白为什么这个主题在列表中,但不在集合里。理想情况下,我希望这个主题能同时出现在这两者中。

4 个回答

3

要么你的Subject类里没有__hash__()这个方法,要么这个方法有问题。你可以试试下面的代码:

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

相关的文档可以在这里找到。

4

一个对象是否属于某个集合,还跟它的哈希值有关。因此,你需要在这个类里正确地实现 __hash__() 方法。

13

这个表达式

Subject("A") in subject_list

会用 Subject.__eq__() 方法将 Subject("A")subject_list 中的每一项进行比较。如果这个方法没有被重写,它默认的行为是总是返回 False,除非这两个对象是同一个实例。也就是说,如果 Subject 没有 __eq__() 方法,上面的表达式总是会返回 False,因为 Subject("A") 是一个新的实例,不可能已经在列表里。

而这个表达式

Subject("A") in subject_set

则相反,它会先使用 Subject.__hash__() 方法找到合适的“桶”,然后再使用 Subject.__eq__() 方法进行比较。如果你没有以与 Subject.__eq__() 兼容的方式定义 Subject.__hash__(),那么这个过程就会失败。

撰写回答