Сделайте список изменчивым и хэш

Объект, который можно хэшировать, нуждается в __hash__ метод, и он имеет хеш-значение, которое никогда не меняется в течение срока его службы.

Списки Python не могут быть хэшируемыми по причинам, которые я полностью игнорирую, и мне интересно, если следующая реализация в порядке или есть некоторые глюки, о которых я не знаю.

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

 a = range(10)
 l = L(range(10))
 print a
 >> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 print l
 >> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 hash(l)
 >> 41889288
 hash(a) # unsurprisingly it returns an error because a list is not hashable
 >> Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'list'

 # lets append a value to l
 l.append(1000)
 print l
 >> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1000]
 isinstance(l, list) # to double check whether l is a List instance
 >> True
 D = {}
 D[l] = "this is a dict with a list as key"
 print D
 {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1000]: 'this is a dict with a list as key'}
 # lets append another value to l
 l.append(-10)
 print D
 >> {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1000, -10]: 'this is a dict with a list as key'}

 # now lets add a normal list to the dict to the dict
 D[a] = "Add a list as key"
 >>Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   TypeError: unhashable type: 'list'

Так что это реализация списка хэширования, которая в значительной степени работает без проблем, и я не понимаю, почему список не может быть хэшируемым в обычном дистрибутиве Python, даже если он все еще изменчив.

NB: Этот вопрос не о том, почему список не может быть использован в качестве словарного ключа. Любое объяснение?

1 ответ

У тебя есть __hash__ метод. Это что-то возвращает. Это возвращает что-то полезное? Посмотрим.

>>> a = L([1, 2])
>>> b = L([1, 2])
>>> a == b
True
>>> s = set([a, b])
>>> s
set([[1, 2], [1, 2]])

Нету! Это нарушает предположения, сделанные любым кодом, который использует hashа именно, что равные объекты имеют одинаковые хэши. Теперь у нас есть набор с двумя равными объектами. Вы можете исправить это, сделав == а также != сравнить по идентичности, хотя тогда вы также потеряете общий заказ и вам придется удалить <, >, <=, а также >=, Это много полезных вещей, которые вы должны взять, чтобы сделать списки осмысленно хашируемыми.

Вы можете - с ограничениями - использовать дамп JSON для сравнения качества контента. Одно ограничение заключается в том, что это работает только для любых данных, сериализуемых в формате JSON.

import json

class HashableList(list):
    def __hash__(self):
        return hash(json.dumps(self, sort_keys=True))

Это хорошо работает в большинстве случаев. В любом случае вам нужно убедиться, что это работает для данных, для которых вы его используете.

Другие вопросы по тегам