Search code examples
pythonclassoperatorsmembership

Object membership in sets


This is really two questions:

  1. Why isn't the membership operator (__contains__) ever being called?

  2. Why is D in nodeList, but not in nodeSet?

My goal is for D to be "in" both nodeList and nodeSet, because it has the same loc as A.

class Node(object):
    def __init__(self, loc):
        self.loc = loc

    def __eq__(self, other):
        print "eq: self.getLoc(): {}, other.getLoc(): {}".format(self.getLoc(),     other.getLoc())
        if self.getLoc() == other.getLoc():
            return True
        return False

    def __contains__(self, other):
        print "contains: self.getLoc(): {}, other.getLoc(): {}".format(self.getLoc(),  other.getLoc())
        if self.getLoc() == other.getLoc():

            return True
        return False

    def setLoc(self, loc):
        self.loc = loc

    def getLoc(self):
        return self.loc


if __name__ == "__main__":
    A = Node((1,1))
    B = Node((2,2))
    C = Node((3,3))

    D = Node((1,1))

    nodeList = [A, B, C]
    nodeSet = set()
    nodeSet.add(A)
    nodeSet.add(B)
    nodeSet.add(C)

    print "A in nodeList: {}".format(A in nodeList)
    print "A in nodeSet: {}".format(A in nodeSet)
    print "D in nodeList: {}".format(D in nodeList)
    print "D in nodeSet: {}".format(D in nodeSet)

This returns True, True, True, False. Apparently, the __contains__ operator is never called. I would like it to return True, True, True, True.

Any other critiques of my code are of course welcome, as I am a python beginner.


Solution

  • See the documentation re __hash__() - in short:

    [I]f [a class] defines __cmp__() or __eq__() but not __hash__(), its instances will not be usable in hashed collections.

    A set is a hashed collection. You'll want to make sure you implement Node.__hash__()