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

Список unhashable, но tuple hashable?

В Как хеш-списки? Мне сказали, что я должен сначала преобразовать в кортеж, например. [1,2,3,4,5] до (1,2,3,4,5).

Итак, первое не может быть хэшировано, но второе может. Почему *


* Я действительно не ищу подробного технического объяснения, а скорее для интуиции

4b9b3361

Ответ 1

В основном, потому что кортежи неизменяемы. Предположим, что следующие работы:

>>> l = [1, 2, 3]
>>> t = (1, 2, 3)
>>> x = {l: 'a list', t: 'a tuple'}

Теперь, что происходит, когда вы делаете l.append(4)? Вы изменили ключ в своем словаре! Издалека! Если вы знакомы с тем, как работают алгоритмы хэширования, это должно вас напугать. С другой стороны, кортежи абсолютно непреложны. t += (1,) может выглядеть так, как будто он модифицирует кортеж, но на самом деле это не так: он просто создает новый кортеж, оставляя ключ словаря неизменным.

Ответ 2

Вы можете полностью выполнить эту работу, но я уверен, вам не понравятся эффекты.

from functools import reduce
from operator import xor

class List(list):
    def __hash__(self):
        return reduce(xor, self)

Теперь посмотрим, что произойдет:

>>> l = List([23,42,99])
>>> hash(l)
94
>>> d = {l: "Hello"}
>>> d[l]
'Hello'
>>> l.append(7)
>>> d
{[23, 42, 99, 7]: 'Hello'}
>>> l
[23, 42, 99, 7]
>>> d[l]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: [23, 42, 99, 7]

изменить: Поэтому я подумал об этом еще немного. Вы можете сделать приведенный выше пример работы, если вы вернете идентификатор списка в качестве его хэш-значения:

class List(list):
    def __hash__(self):
        return id(self)

В этом случае d[l] даст вам 'Hello', но ни d[[23,42,99,7]], ни d[List([23,42,99,7])] не будет (потому что вы создаете новый [Ll]ist.

Ответ 3

Поскольку список изменен, если вы его изменяете, вы также измените его хэш, который разрушит точку хэша (например, в наборе или клавише dict).

Ответ 4

Поскольку списки изменяемы, а кортежи - нет.

Ответ 5

Не каждый кортеж hashable. Например, кортеж содержит список как элемент.

x = (1,[2,3])
print(type(x))
print(hash(x))