Подтвердить что ты не робот

Почему я не могу называть hash() по явно хешируемому методу нераскрывающегося экземпляра?

Скажем, у меня есть словарь:

>>> d = {}

Он имеет метод clear():

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

... который имеет атрибут __hash__:

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

... который можно вызывать:

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

Так почему я не могу его хешировать?

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

Примечание: Я знаю, что объекты dict не сотрясаются - мне любопытно, почему это ограничение распространяется на их методы, хотя, как отмечено выше, они, похоже, заявляют об обратном?

4b9b3361

Ответ 1

Это связанный метод, и связанные методы имеют ссылку на self, например. словарь. Это делает метод un-hashable.

Вы можете использовать метод unbound dict.clear:

>>> 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

Методы для экземпляров, которые являются хешируемыми, сами будут хешируемыми, поэтому тип объекта для встроенных методов привязки реализует метод __hash__, но повышает значение TypeError, когда атрибут __self__ не является хешируемым. Это согласуется с документацией метода object.__hash__; если вы можете установить его на None или вообще не реализовать его, то это предпочтительнее, но для тех случаев, когда хеширование известно только во время выполнения, повышение TypeError является единственным доступным вариантом.

Ответ 2

Мартин прав, поскольку он очень часто. Если у вас есть подкласс dict, который реализует метод __hash__, даже связанные методы становятся хешируемыми
class MyHashableDict(dict):
    def __hash__(self):
        return 42

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

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

Вывод:

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