Що означає "хешируемость" в Python?


194

Я спробував шукати Інтернет, але не зміг знайти значення хешируемого.

Коли кажуть, що об’єкти є hashableчи hashable objectsщо це означає?


1
Дивіться документацію щодо хешируемости та __hash__()методу .
ʇsәɹoɈ

5
який шукає об’єкти, що містяться, або щось подібне, але жодне з посилань не пояснює, що насправді означає "
hashable"

Відповіді:


181

З словника Python :

Об'єкт є хешируемим, якщо він має хеш-значення, яке ніколи не змінюється протягом свого життя (йому потрібен __hash__()метод), і його можна порівняти з іншими об'єктами (йому потрібен __eq__()або __cmp__()метод). Об'ємні об'єкти, які порівнюють рівні, повинні мати однакове хеш-значення.

Можливість використання об'єкта використовується як ключ словника та набір елементів, оскільки ці структури даних використовують хеш-значення всередині.

Усі незмінні вбудовані об'єкти Python є хедж-енд, а змінні контейнери (наприклад, списки чи словники) не є. Об'єкти, які є примірниками визначених користувачем класів, за замовчуванням є хешируемими; всі вони порівнюють нерівні, і хеш-цінність їхня id().


2
якщо він має hash valueзараз те, що має хеш-значення. ви можете навести приклад
user1755071,

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).
davidA

2
Я знаю, що це стара публікація, але варто згадати, що скопійований тут словник не зовсім коректний. Ви можете помістити змінений об'єкт (наприклад, список) всередині кордону. Кортеж все ще незмінний, але ви можете змінити список всередині нього, так що він не підлягає застосуванню. Спробуйте hash((1, [2, 3]))побачити це в дії. Я опублікував запит на виправлення запису з глосарію на предмет хешавання.
Джон Ріель

102

У всіх відповідях тут є чітке робоче пояснення хешируемих об'єктів у python, але я вважаю, що потрібно спершу зрозуміти термін Хешинг.

Хешинг - це концепція в галузі інформатики, яка використовується для створення високопродуктивних, псевдоструктур даних з випадковим доступом, де потрібно швидко зберігати та отримувати доступ до них.

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

Отже, ви можете замість цього використовувати масив розміром 100 та використовувати хеш-функцію для набору набору значень для тих самих індексів, і ці значення можуть зберігатися у пов'язаному списку. Це забезпечує продуктивність, схожу на масив.

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

Більш детально див. Https://en.wikipedia.org/wiki/Hash_function

Ось ще одна хороша довідка: http://interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html


1
Це цікава перспектива щодо хешування. Я не думав про це таким чином.
ювгін

@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, коли ви створюєте екземпляр об'єктів, які є хешируемими, незмінне значення також обчислюється відповідно до членів або значень екземпляра. Наприклад, це значення може бути використане як ключ у диктаті, як показано нижче:

>>> 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 це означає, що об'єкт може бути членами наборів для повернення індексу. Тобто вони мають унікальну особу / ідентифікатор.

наприклад, у python 3.3:

Структура даних Списки не є доступними, але структура даних Tuples є хешируемой.


Хеш - це не те саме id, що (приблизно) адреса об'єкта в пам'яті.
poolie

3

Гашебний = здатний хешировать.

Гаразд, що хеш? Хеш-функція - це функція, яка приймає об'єкт, наприклад, рядок типу "Python", і повертає код фіксованого розміру. Для простоти припустимо, що повернене значення є цілим числом.

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

Але хеш ("Java") повертає 1753925553814008565. Отже, якщо об'єкт, який я хешую, зміниться, то і результат. З іншого боку, якщо об'єкт, який я хешую, не зміниться, результат залишається таким же.

Чому це має значення?

Ну, наприклад, словники Python вимагають, щоб ключі були незмінними. Тобто, ключі повинні бути об'єктами, які не змінюються. Струни незмінні в Python, як і інші основні типи (int, float, bool). Кортежі та фрозенсети також непорушні. Списки, з іншого боку, не є незмінними (тобто вони є змінними), оскільки ви можете їх змінити. Аналогічно, дикти змінюються.

Тож, коли ми говоримо, що щось є грішним, ми маємо на увазі, що це незмінне. Якщо я спробую передати змінний тип функції хеш (), це не вдасться:

>>> 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") в різних процесах.
D Хадсон

2

У Python будь-який незмінний об'єкт (такий як ціле число, булева, рядок, кортеж) є придатним для зміни, тобто його значення не змінюється протягом його життя. Це дозволяє Python створювати унікальне хеш-значення для його ідентифікації, яке може використовуватися словниками для відстеження унікальних ключів та наборів для відстеження унікальних значень.

Ось чому Python вимагає від нас використовувати незмінні типи даних для ключів у словнику.


-1

Для створення таблиці хешування з нуля всі значення повинні бути встановлені на "None" та змінені, коли виникає вимога. Об'ємні об'єкти відносяться до модифікованих типів даних (Словник, списки тощо). Набори з іншого боку не можуть бути повторно ініціалізовані, коли їх присвоєно, тому набори не підлягають перегляду. Тоді як варіант set () - Заморожений набір () - є хешируемим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.