25

Let's say I have a dictionary:

>>> d = {}

It has a method clear():

>>> d.clear
<built-in method clear of dict object at 0x7f209051c988>

... which has a __hash__ attribute:

>>> d.clear.__hash__
<method-wrapper '__hash__' of builtin_function_or_method object at 0x7f2090456288>

... which is callable:

>>> callable(d.clear.__hash__)
True

So why can't I hash it?

>>> hash(d.clear)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

Note: I know that dict objects are unhashable – I'm curious as to why this restriction extends to their methods, even though, as noted above, they appear to claim otherwise?

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160

2 Answers2

33

It is a bound method, and bound methods have a reference to self, e.g. the dictionary. This makes the method un-hashable.

You can hash the unbound dict.clear method:

>>> d = {}
>>> d.clear.__self__
{}
>>> d.clear.__self__ is d
True
>>> hash(d.clear)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> hash(dict.clear)
-9223372036586189204

Methods on instances that are hashable will themselves be hashable, so the object type for built-in bound methods implements a __hash__ method but raises TypeError when the __self__ attribute is not hashable. This is consistent with the object.__hash__ method documentation; if you can set it to None or not implement it at all then that is preferable but for these cases where the hashability is only known at runtime raising a TypeError is the only option available.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
11

Martijn is right as he very often is. If you have a dict subclass that does implement the __hash__ method, even the bound methods become hashable

class MyHashableDict(dict):
    def __hash__(self):
        return 42

x = MyHashableDict()
print(x, hash(x), hash(x.clear))

y = {}
print(y, hash(y.clear))

Output:

{} 42 287254
Traceback (most recent call last):
  File "y.py", line 9, in <module>
    print(hash(y.clear))
TypeError: unhashable type: 'dict'