Чи є словник Python прикладом хеш-таблиці?


187

Однією з основних структур даних в Python є словник, який дозволяє записувати "клавіші" для пошуку "значень" будь-якого типу. Чи реалізується це внутрішньо як хеш-таблиця? Якщо ні, то що це?


2
Якщо вас цікавлять технічні деталі, одна стаття в Beautiful Code стосується внутрішніх можливостей dictреалізації Python .
Торстен Марек

Це було одне з моїх улюблених розділів у Beautiful Code.
DGentry

4
Ось бесіда Брендона Крейга Родоса, яка обговорює, як працює словник python, youtube.com/watch?v=C4Kc8xzcA68 .
шандола

Я деякий час шукав схему, що представляє диктант, який дешифрує реалізацію в пам'яті та CPython. Дякуємо за посилання на книгу!
Чень А.

Відповіді:


239

Так, це хеш-карта або хеш-таблиця. Ви можете прочитати опис реалізації диктону python, написаний Тімом Петерсом, тут .

Ось чому ви не можете використовувати щось "не доступне" як клавішу dict, як список:

>>> a = {}
>>> b = ['some', 'list']
>>> hash(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list objects are unhashable
>>> a[b] = 'some'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list objects are unhashable

Ви можете прочитати більше про хеш-таблиці або перевірити, як це було реалізовано в python і чому він реалізований таким чином .


1
Тім Пітерс з'єднує шви, які потрібно зламати, чи є там чисте посилання?
Метт Алькок

1
@MattAlcock: я оновив посилання. Іноді (як правило, через те, що хтось хоче, щоб їх адресу електронної пошти було десь видалено) архіви списку python перебудовуються, а ідентифікатори електронних листів змінюються, таким чином порушуючи ці посилання. Адміністратори підоторгів, як правило, намагаються цього уникнути.
Martijn Pieters

Але за допомогою .keys()можна отримати список ключів. Справжня хеш-таблиця не зберігатиме ключі, а хеші, щоб заощадити місце.
noɥʇʎԀʎzɐɹƆ

Більш повний опис реалізації python dict тут: laurentluce.com/posts/python-dictionary-implementation
Даніель Голдфарб

32

У словнику Python повинно бути більше, ніж пошук таблиці на хеш (). Шляхом грубого експерименту я виявив таке хеш-зіткнення :

>>> hash(1.1)
2040142438
>>> hash(4504.1)
2040142438

Але він не порушує словник:

>>> d = { 1.1: 'a', 4504.1: 'b' }
>>> d[1.1]
'a'
>>> d[4504.1]
'b'

Перевірка обгрунтованості:

>>> for k,v in d.items(): print(hash(k))
2040142438
2040142438

Можливо, є інший рівень пошуку за межами хеша (), який дозволяє уникнути зіткнень між клавішами словника. А може бути, dict () використовує інший хеш.

(До речі, це в Python 2.7.10. Та сама історія в Python 3.4.3 та 3.5.0 із зіткненням у hash(1.1) == hash(214748749.8).)


14
Тож зіткнення неминучі. Набір S може містити нескінченно велику кількість предметів, і ви хочете, щоб він перебрався на номер, який може зберігати комп'ютер. Кожна зручна реалізація хеш-таблиці вирішує зіткнення, причому два найчастіші методи: а) відкрита адресація та б) ланцюжок. Тільки тому, що він не використовує ідеальний хеш, не означає, що це не хеш-таблиця.
TurnipEntropy

1
Зіткнення відбудуться взагалі, оскільки існує нескінченно можливих значущих значень та кінцевих хеш-кодів. Навіть хеш-таблиця повинна якось впоратися зіткненням.
Янфен Лю

3
@YanfengLiu Я вважаю, що це точно такі самі пункти, як зроблено TurnipEntropy.
Боб Штейн

1
У Python 3.7, схоже, є 2E20 мінус 1 можливих хеш-значень. Від -1E20 мінус 1 до (+) 1E20 мінус 1. Спробуйте. hash('I wandered lonely as a cloud, that drifts on high o\'er vales and hills, when all at once, I saw a crowd, a host of golden daffodils.')Це дає 19-значний десятковий знак - -4037225020714749784якщо ви досить вигадливі для догляду. Продовжуйте своїми словами, діти, а хеш - це все-таки 19-значне число. Я припускаю, що в Python є обмеження по довжині рядка, який ви можете хешувати, але безпечно сказати набагато більше можливих рядків, ніж можливі значення. І hash(False)= 0 до речі.
Буде Кроксфорд


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