【问题标题】:How is membership testing different for a list and a set?列表和集合的成员资格测试有何不同?
【发布时间】:2011-07-10 23:21:10
【问题描述】:

我无法弄清楚为什么这些断言中的第一个是正常的,而第二个会引发错误。

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,在另一个 UnitTest 中我验证了 Subject("A") == Subject("A")。我真的无法弄清楚为什么主题在列表中而不是在集合中。理想情况下,我希望这两个主题都有。

【问题讨论】:

    标签: python list set member


    【解决方案1】:

    表达式

    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__(),这将失败。

    【讨论】:

    • 谢谢!在 Subject 类中实现一个 __hash__() 函数解决了这个问题。
    【解决方案2】:

    集合中的成员身份还取决于对象的哈希值,因此您必须在类上适当地实现__hash__() 方法。

    【讨论】:

      【解决方案3】:

      要么你的 Subject 类中没有 __hash__() 方法,要么它很狡猾。试试这个:

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

      文档是here

      【讨论】:

        【解决方案4】:

        要在集合中使用这些,您必须确保 Subject 是正确可散列的。如果您自己没有定义__hash__,它将简单地采用id,这对于不同的实例是不同的。 __hash__ 应该定义为相等的对象具有相等的哈希值。

        【讨论】:

          猜你喜欢
          • 2011-07-11
          • 1970-01-01
          • 2012-11-28
          • 2021-10-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-05
          • 1970-01-01
          相关资源
          最近更新 更多