Python 2: different meaning of the in keyword for sets and lists

Consider this snippet:

class SomeClass(object): def __init__(self, someattribute="somevalue"): self.someattribute = someattribute def __eq__(self, other): return self.someattribute == other.someattribute def __ne__(self, other): return not self.__eq__(other) list_of_objects = [SomeClass()] print(SomeClass() in list_of_objects) set_of_objects = set([SomeClass()]) print(SomeClass() in set_of_objects) 

which is rated as:

 True False 

Can someone explain why the in keyword has a different meaning for sets and lists? I would expect both to return True, especially when the type being tested has certain equality methods.

+8
python equality list set
source share
3 answers

The meaning is the same, but the implementation is different. Lists just check every object, checking for equality, so it works for your class. Sets hash objects first, and if they do not implement the hash properly, the set looks inoperative.

Your class defines __eq__ , but does not define __hash__ , and therefore will not work properly for collections or as dictionary keys. The rule for __eq__ and __hash__ is that two objects that __eq__ as True should also have equal hashes. By default, a hash of objects based on their memory address. Thus, your two objects, equal to your definition, do not provide the same hash, so they violate the __eq__ and __hash__ .

If you provide an __hash__ implementation, it will work fine. For your sample code, this could be:

 def __hash__(self): return hash(self.someattribute) 
+15
source share

Pretty much any hash table implementation, including Python, if you override the equality method, you must override the hash method (in Python, this is __hash__ ). The in operator for lists simply checks the equality with each element of the list, which the in operator for sets first hashes the object you are looking for, checks the object in this slot of the hash table and then checks for equality if there is something in the slot. Thus, if you override __eq__ without overriding __hash__ , you are not guaranteed that the in operator for sets will check the correct slot.

+3
source share

Define the __hash__() method that matches your __eq__() method. An example .

+1
source share

All Articles