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