0

I use this code to judge object can be hashed or not in python:

#hashable
number1 = 1.2 #float
number2 = 5 #int
str1 = '123' #str
tuple1 = (1,2,3) #tuple

# unhashable
list1 = [1,2,3] #list
print(hash(list1)) #TypeError: unhashable type: 'list'
set1 = {1,2,3} #set
print(hash(set1)) #TypeError: unhashable type: 'set'
dict1 = {'a':1,'b':2,'c':3} #dict
print(hash(dict1)) #TypeError: unhashable type: 'dict'

def HashableOrUnhashable(obj):
    '''
    This function will return True or False, the object can be hashed or not be hashed.
    '''
    try:
        hash(obj)
        return True
    except Exception as ex:
        return False


result = HashableOrUnhashable(someObj) #Can be str,int,float,list,tuple,set,dict or others.
if result:
    print('This object can be hashed.')
else:
    print('This object can not be hashed.')

I think my writing in the function HashableOrUnhashable is not good.

So how should I judge whether an object can be hashed or not?

2 Answers2

1

Your function is correct. Here are some general guidelines:

  • Basic built-in types that are not containers are hashable.
  • Immutable containers (like frozenset and tuple) are hashable if (and only if) all the items they contain are also hashable.
  • User-defined classes are usually hashable.
  • Mutable built-in containers are unhashable.

See also the Python glossary.

Jasmijn
  • 9,370
  • 2
  • 29
  • 43
0

Hashable in Python means that objects can be hashed && same hash value for two objects means that both objects are equal.

Here is a user-defined class which has been deliberately tempered by overriding the hash dunder method. Now the objects of this class return equal for same name, even though their ids are different.

class A:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __hash__(self):
        return id(self)

    def __eq__(self, b):
        return self.name == b.name

if __name__ == '__main__':
    a = A('testuser', 30)
    print(f'hash is: {hash(a)}')
    print(id(a))
    b = A('testuser', 40)
    print(f'hash is: {hash(b)}')
    print(id(b))
    print (a==b)

This class objects will return you a hash the objects are not hashable because x==y even though hash(x)!=hash(y)

So take a look at you objects class definition also to ensure that they are hashable.

If they do not override the hash and eq dunder methods, they are hashable.

lllrnr101
  • 2,288
  • 2
  • 4
  • 15
  • I agree that the documentation says what you say it does, but I think that one might be able to think of special circumstances where you might want a less fine-grained equality/equivalence relation while maintaining a more strict definition of ultimate identity reflected in hashing. e.g. you might have metadata inconsequential to comparisons but that you may want to uniquely preserve in terms of keying. This doesn't really seem to be a strict rule like "don't change a hash value after an object is created", seems more like a recommendation that uses the word requirement. Just my opinion. – Matt Miguel Feb 02 '21 at 07:59
  • I expect that the OP is looking for a purely programatic way to determine hashability. So while I get what you're saying, and I agree, I don't think what you're saying applies to this question. I think that the OP is just going to have to assume that any object that "can be hashed" is also "properly hashable", if that's important to them. – CryptoFool Feb 02 '21 at 08:00
  • I asked the OP for the use case but it seems the problem has come from the boss without clear directions. So I wanted to inform that when it comes to User-defined classes, behavior by default is hashable (don't override anything and get hashable class objects in return) but should be careful so as not to get burnt later. – lllrnr101 Feb 02 '21 at 08:04
  • @MattMiguel if `a == b` doesn't imply `hash(a) == hash(b)` then you can get hard-to-reproduce aliasing bugs, depending on the specific implementation of dictionary lookups. I'd say the documentation uses the word "required" for good reason here. – Jasmijn Feb 02 '21 at 09:17