Что означает «хэшируемый» в Python?


194

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

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


1
Смотрите документацию по hashable и __hash__()методу .
ɈsәɹoɈ

5
который ищет доступные объекты или что-то, но ни одна из ссылок не объясняет, что на самом деле означает
hashable

Ответы:


181

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

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

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

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


2
если он имеет hash valueсейчас, что является хэш-значением.
Можете

2
@ user55711: Здесь хеш-значение является результатом вызова __hash__(). В более общем плане см. En.wikipedia.org/wiki/Hash_function
NPE

16
@TorstenBronger: потому что два неравных объекта могут хэшировать одно и то же значение. Другими словами, хеширование с потерями.
NPE

1
В python-2.7.12 результат id(object)равен 16x результату object.__hash__(). Таким образом, выдержка из глоссария является неправильной для этой версии - значение хеша - нет id(), но оно получено из него (как действительно отмечено в обновленных документах для Python 2.7.12).
Дэвид

2
Я знаю, что это старый пост, но стоит упомянуть, что скопированная здесь запись глоссария не совсем верна. Вы можете поместить изменяемый объект (например, список) в кортеж. Кортеж по-прежнему неизменен, но вы можете изменить список внутри него, чтобы он не был хэшируемым. Попробуйте hash((1, [2, 3]))увидеть это в действии. Я отправил запрос на исправление записи глоссария для hashable.
Джон Рил

102

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

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

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

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

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

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

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


1
Это интересный взгляд на хеширование. Я не думал об этом таким образом.
yuvgin

Хеш-таблицы @yuvgin часто используются для реализации разреженных массивов (например, приведенный здесь пример).
Эли Корвиго

@EliKorvigo Мне нравится думать о регулярных массивах как о просто высоко оптимизированных версиях хеш-таблицы.
Марк Рэнсом

1
Можете ли вы дать какой-нибудь простой код относительно сценария массива телефонных номеров, чтобы прояснить концепцию хеширования?
Истак Ахмед

18

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

#x = hash(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

Недавно я обнаружил, что Ellipsisэто также неизменный тип и может использоваться в качестве ключа для dict.
Габор Фекете

Можно использовать даже определенные пользователем классы, но только их имена, а не экземпляры. Например:hash(MyClass)
Габор Фекете

1
@ GáborFekete экземпляры пользовательских классов могут быть хэшируемыми, если их классы реализуют __hash__и __eq__. Более того, все пользовательские классы реализуют эти методы (и, следовательно, являются хешируемыми), потому что они наследуют методы от object(универсального базового класса).
Эли Корвиго

7

В моем понимании, согласно глоссарию 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'>

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


4

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

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


26
это было бы более полезно в виде текста, а не изображения
baxx

7
это неправильный ответ. id () показывает ссылочный адрес в памяти, это не хеш-значение. Для получения хеша используйте функцию __hash __ (). Например: t1 .__ хэш __ ()
Влад

@ascentman Не стесняйтесь редактировать ответ, который вы считаете неправильным. Ваше изменение будет рецензировано, и, если оно будет принято, вы получите небольшое вознаграждение за него.
XavierStuvw

4

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

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

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


Хеш не совпадает с id, который является (приблизительно) адресом объекта в памяти.
Poolie

3

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

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

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

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

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

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

Поэтому, когда мы говорим, что что-то хэшируемо, мы имеем в виду, что оно неизменно. Если я попытаюсь передать изменяемый тип в функцию 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

1
Обратите внимание, что python случайным образом запускает алгоритм хеширования в начале каждого процесса. Следовательно, вы фактически получите разные значения хеш-функции, если дважды запустите хеш-код ('Python') в разных процессах.
Г Хадсон

2

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

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


-1

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.