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

Почему Python не может хешировать?

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

>>> set([ set() ])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'

Есть ли веская причина, что наборы Python не хешируются?

4b9b3361

Ответ 1

Как правило, в Python хешируются только неизменяемые объекты. Неизбежный вариант set() - frozenset() - hashable.

Ответ 2

Потому что они изменяемы.

Если они были хешируемыми, хэш может бесшумно стать "недействительным", и это в значительной степени сделает хэширование бессмысленным.

Ответ 3

В документах Python:

hashable
 Объект хешируется, если он имеет значение хеша, которое никогда не изменяется в течение своей жизни (для этого требуется хеш()), и его можно сравнить с другими объектами (требуется eq() или cmp()). Хешируемые объекты, сравнивающие равные должно иметь одинаковое значение хеша.

Hashability позволяет использовать объект как ключ словаря и набор элементов, поскольку эти структуры данных используют хэш-значение внутри.

Все неиспользуемые встроенные Pythons объекты хешируются, а не изменяются контейнеры (например, списки или словари). Объекты, которые экземпляры пользовательских классов hashable по умолчанию; все они сравнивают неравные, а их хэш-значение - их Идентификатор().

Ответ 4

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

from collections import Hashable, MutableSet, MutableSequence, MutableMapping

def make_hashdict(value):
    """
    Inspired by /info/45622/python-hashable-dicts
     - with the added bonus that it inherits from the dict type of value
       so OrderedDict maintain their order and other subclasses of dict() maintain their attributes
    """
    map_type = type(value)

    class HashableDict(map_type):
        def __init__(self, *args, **kwargs):
            super(HashableDict, self).__init__(*args, **kwargs)
        def __hash__(self):
            return hash(tuple(sorted(self.items())))

    hashDict = HashableDict(value)

    return hashDict


def make_hashable(value):
    if not isinstance(value, Hashable):
        if isinstance(value, MutableSet):
            value = frozenset(value)
        elif isinstance(value, MutableSequence):
            value = tuple(value)
        elif isinstance(value, MutableMapping):
            value = make_hashdict(value)

        return value

my_set = set()
my_set.add(make_hashable(['a', 'list']))
my_set.add(make_hashable({'a': 1, 'dict': 2}))
my_set.add(make_hashable({'a', 'new', 'set'}))

print my_set

Реализация My HashableDict - это самый простой и наименее строгий пример из здесь. Если вам нужен более продвинутый HashableDict, который поддерживает травление и другие вещи, проверьте многие другие реализации. В моей версии выше я хотел сохранить исходный класс dict, тем самым сохраняя порядок OrderedDicts. Я также использую AttrDict от здесь для доступа к атрибутам.

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