Что вы подразумеваете под hashable в Python?

Я пытался найти в Интернете, но не смог найти значение hashable.

Когда они говорят, что объекты hashable или же hashable objects что это значит?

11 ответов

Решение

Из глоссария Python:

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

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

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

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

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

Например, если у вас есть 10000 телефонных номеров, и вы хотите сохранить их в массиве (который представляет собой последовательную структуру данных, которая хранит данные в смежных местах памяти и обеспечивает произвольный доступ), но у вас может не быть необходимого количества непрерывных данных. места памяти.

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

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

Для получения дополнительной информации обратитесь к https://en.wikipedia.org/wiki/Hash_function

Вот еще одна хорошая справка: http://interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html

Все, что не является изменчивым (изменяемое означает, что оно может измениться) может быть хешировано. Помимо хеш-функции, которую нужно искать, например, в классе. dir(tuple) и ищет __hash__ метод, вот несколько примеров

#x = has(set([1,2])) #set unhashable
x = hash(frozenset([1,2])) #hashable
#x = hash(([1,2], [2,3])) #tuple of mutable objects, unhashable
x = hash((1,2,3)) #tuple of immutable objects, hashable
#x = hash()
#x = hash({1,2}) #list of mutable objects, unhashable
#x = hash([1,2,3]) #list of immutable objects, unhashable

Список неизменяемых типов:

int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes

Список изменяемых типов:

list, dict, set, bytearray, user-defined classes

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

>>> tuple_a = (1,2,3)
>>> tuple_a.__hash__()
2528502973977326415
>>> tuple_b = (2,3,4)
>>> tuple_b.__hash__()
3789705017596477050
>>> tuple_c = (1,2,3)
>>> tuple_c.__hash__()
2528502973977326415
>>> id(a) == id(c)  # a and c same object?
False
>>> a.__hash__() == c.__hash__()  # a and c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'

мы можем обнаружить, что хеш-значения tuple_a и tuple_c одинаковы, так как они имеют одинаковые члены. Когда мы используем tuple_a в качестве ключа в dict_a, мы можем обнаружить, что значение dict_a[tuple_c] одинаково, что означает, что, когда они используются в качестве ключа в dict, они возвращают одно и то же значение, потому что значения хеша тот же самый. Для тех объектов, которые не являются хэшируемыми, хэш метода определен как None:

>>> type(dict.__hash__) 
<class 'NoneType'>

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

Hashable = возможность хеширования.

Хорошо, что такое хеширование? Хеширующая функция - это функция, которая принимает объект, например строку, такую ​​как "Python", и возвращает код фиксированного размера. Для простоты предположим, что возвращаемое значение является целым числом.

Когда я запускаю hash('Python') в Python 3, я получаю 5952713340227947791 в результате. Различные версии Python могут свободно изменять базовую хеш-функцию, поэтому вы, вероятно, получите другое значение. Важно то, что независимо от того, сколько раз я сейчас запускаю hash('Python'), я всегда получу один и тот же результат с той же версией Python.

Но hash('Java') возвращает 1753925553814008565. Итак, если объект, который я хэширую, изменяется, то же самое и с результатом. С другой стороны, если объект, который я хэширую, не изменяется, результат остается прежним.

Почему это важно?

Что ж, словари Python, например, требуют, чтобы ключи были неизменными. То есть ключи должны быть объектами, которые не меняются. Строки неизменны в Python, как и другие базовые типы (int, float, bool). Кортежи и фрозенсеты также неизменны. Списки, с другой стороны, не являются неизменяемыми (т. Е. Изменяемыми), потому что вы можете их изменять. Точно так же dicts изменчивы.

Поэтому, когда мы говорим, что что-то хешируемое, мы имеем в виду, что это неизменяемо. Если я попытаюсь передать изменяемый тип функции hash(), произойдет сбой:

>>> hash('Python')
1687380313081734297
>>> hash('Java')
1753925553814008565
>>>
>>> hash([1, 2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash({1, 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> hash({1 : 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
>>> hash(frozenset({1, 2}))
-1834016341293975159
>>> hash((1, 2))
3713081631934410656

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

Вот почему Python требует, чтобы мы использовали неизменяемые типы данных для ключей в словаре.

Смотрите документацию на хэш и __hash__() метод.

Позвольте мне привести вам рабочий пример для понимания хэшируемых объектов в python. Для этого примера я беру 2 кортежа. Каждое значение в кортеже имеет уникальное значение хеша, которое никогда не изменяется в течение жизни. Таким образом, на основе этого имеет значение сравнение двух кортежей. Мы можем получить хеш-значение элемента кортежа, используя Id().

Сравнение двух кортежейЭквивалентность между двумя кортежами

В python это означает, что объект может быть членом множеств для возврата индекса. То есть они имеют уникальную личность / идентификатор.

например, в питоне 3.3:

Списки структуры данных не являются хэшируемыми, но кортежи структуры данных являются хэшируемыми.

В дополнение к другим ответам: в глоссарии Python говорится, что «объекты, которые являются экземплярами определяемых пользователем классов, по умолчанию хэшируются». Но он также говорит: «Хешируемые объекты, которые сравниваются равными, должны иметь одинаковое хеш-значение».

При этом, если вы реализуете__eq__-Метод без реализации__hash__-Метод вашего объекта не будет хэшироваться. В противном случае получение хэша изid()не будет гарантировать, что для двух объектов, которые сравниваются равными, генерируется один и тот же хэш (id(a) != id(b)ноa == b)

      >>> class Foo(object):
...     def __eq__(self, other): pass
... 
>>> 
>>> class Bar(object):
...     pass
... 
>>> f = Foo()
>>> b = Bar()
>>> 
>>> hash(f)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Foo'
>>> hash(b)
8758325844794

Чтобы создать хеш-таблицу с нуля, все значения должны быть установлены на "Нет" и изменены при возникновении требования. Хэшируемые объекты относятся к изменяемым типам данных (словарь, списки и т. Д.). С другой стороны, наборы нельзя повторно инициализировать после назначения, поэтому наборы не могут быть хешированы. Тогда как вариант set() - frozenset() - хешируемый.

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