What makes a user-defined class unhashable? What makes a user-defined class unhashable? python python

What makes a user-defined class unhashable?


Simply setting the __hash__ method to that of the tuple class is not enough. You haven't actually told it how to hash any differently. tuples are hashable because they are immutable. If you really wanted to make you specific example work, it might be like this:

class X2(list):    def __hash__(self):        return hash(tuple(self))

In this case you are actually defining how to hash your custom list subclass. You just have to define exactly how it can generate a hash. You can hash on whatever you want, as opposed to using the tuple's hashing method:

def __hash__(self):    return hash("foobar"*len(self))


From the Python3 docs:

If a class does not define an __eq__() method it should not define a __hash__() operation either; if it defines __eq__() but not __hash__(), its instances will not be usable as items in hashable collections. If a class defines mutable objects and implements an __eq__() method, it should not implement __hash__(), since the implementation of hashable collections requires that a key’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket).

Ref: object.__hash__(self)

Sample code:

class Hashable:    passclass Unhashable:    def __eq__(self, other):        return (self == other)class HashableAgain:    def __eq__(self, other):        return (self == other)    def __hash__(self):        return id(self)def main():    # OK    print(hash(Hashable()))    # Throws: TypeError("unhashable type: 'X'",)    print(hash(Unhashable()))      # OK    print(hash(HashableAgain()))


What you could and should do, based on your other question, is:don't subclass anything, just encapsulate a tuple. It's perfectly fine to do so in the init.

class X(object):    def __init__(self, *args):        self.tpl = args    def __hash__(self):        return hash(self.tpl)    def __eq__(self, other):        return self.tpl == other    def __repr__(self):        return repr(self.tpl)x1 = X()s = {x1}

which yields:

>>> sset([()])>>> x1()