How to implement __eq__ for set inclusion test?

2019-04-21 14:04发布

I am running into an issue where I'm adding an instance to a set and then later testing to see whether or not that object exists in that set. I've overridden __eq__() but it doesn't get called during the inclusion test. Do I have to override __hash__() instead? If so, how would I implement __hash__() given that I need to hash the tuple, the list, and the dictionary?

class DummyObj(object):

    def __init__(self, myTuple, myList, myDictionary=None):
        self.myTuple = myTuple
        self.myList = myList
        self.myDictionary = myDictionary

    def __eq__(self, other):
        return self.myTuple == other.myTuple and \
            self.myList == other.myList and \
            self.myDictionary == other.myDictionary

    def __ne__(self, other):
        return not self.__eq__(other)

if __name__ == '__main__':

    list1 = [1, 2, 3]
    t1    = (4, 5, 6)
    d1    = { 7 : True, 8 : True, 9 : True }
    p1 = DummyObj(t1, list1, d1)

    mySet = set()

    mySet.add(p1)

    if p1 in mySet:
        print "p1 in set"
    else:
        print "p1 not in set"

2条回答
做个烂人
2楼-- · 2019-04-21 14:43

Well, my guess would be __eq__ or __ne__ may not called by python when comparing objects using the 'in' operator. I'm not positive what the specific "rich comparison" operator would be, looking at the documentation, but overriding __cmp__ should solve your problem as python uses it by default to perform object comparisons if a more suitable "rich comparison" operator is not implemented.

查看更多
贪生不怕死
3楼-- · 2019-04-21 14:50

From the documentation on sets:

The set classes are implemented using dictionaries. Accordingly, the requirements for set elements are the same as those for dictionary keys; namely, that the element defines both __eq__() and __hash__().

The __hash__ function documentation suggests xor-ing the hashes of components together. As others have mentioned, it's generally not a good idea to hash mutable objects, but if you really need to, this works:

class DummyObj(object):

    ...

    def __hash__(self):
        return (hash(self.myTuple) ^
                hash(tuple(self.myList)) ^
                hash(tuple(self.myDictionary.items())))

And checking to see if it works:

p1 = DummyObj(t1, list1, d1)
p2 = DummyObj(t1, list1, d1)
mySet = set()
mySet.add(p1)

print "p1 in set", p1 in mySet
print "p2 in set", p2 in mySet

This prints:

$ python settest.py 
p1 in set True
p2 in set True
查看更多
登录 后发表回答