Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is membership testing different for a list and a set?

I'm having trouble with figuring out why the first of these assertions is OK and the second raises an error.

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)

Here is the error:

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>])

The test for equality in the Subject class is simply self.name == other.name, and in another UnitTest I verify that Subject("A") == Subject("A") . I really can't figure out why the subject is in the list and not in the set. Ideally I'd like the subject to be in both.

like image 234
rtclay Avatar asked Mar 08 '11 09:03

rtclay


1 Answers

The expression

Subject("A") in subject_list

will compare Subject("A") to each entry in subject_list using the Subject.__eq__() method. If this method is not overwritten, it defaults to always return False unless the two operands are the same object. The above expression would always return False if Subject lacked a __eq__() method, since Subject("A") is a new instance which cannot already be in the list.

The expression

Subject("A") in subject_set

on the contrary will use Subject.__hash__() first to find the right bucket, and use Subject.__eq__() only after this. If you did not define Subject.__hash__() in a way compatible with Subject.__eq__(), this will fail.

like image 176
Sven Marnach Avatar answered Nov 15 '22 21:11

Sven Marnach