Является ли словарь Python примером хеш-таблицы?

Одной из основных структур данных в Python является словарь, который позволяет записывать «ключи» для поиска «значений» любого типа. Это реализовано внутри как хеш-таблица? Если нет, то что это?


person Tommy Herbert    schedule 22.09.2008    source источник
comment
Если вас интересуют технические детали, одна статья в Красивый код посвящена внутреннему устройству Python. dict реализация.   -  person Torsten Marek    schedule 22.09.2008
comment
Это была одна из моих любимых глав в Beautiful Code.   -  person DGentry    schedule 22.09.2008
comment
Вот доклад Брэндона Крейга Роудса о том, как работает словарь Python, youtube.com/watch?v= C4Kc8xzcA68.   -  person chandola    schedule 27.05.2017
comment
Я некоторое время искал диаграмму, представляющую dict, которая описывает реализацию в памяти и CPython. Спасибо за ссылку на книгу!   -  person Chen A.    schedule 30.03.2018


Ответы (4)


Да, это хеш-отображение или хэш-таблица. Вы можете прочитать описание реализации python dict, написанное Тимом Питерсом, здесь.

Вот почему вы не можете использовать что-то «не хешируемое» в качестве ключа 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 и почему это реализовано таким образом.

person nosklo    schedule 22.09.2008
comment
Ссылка Тима Питерса, похоже, сломана, есть ли чистая ссылка? - person Matt Alcock; 25.06.2012
comment
@MattAlcock: я обновил ссылку. Иногда (обычно из-за того, что кто-то хочет где-то удалить свой адрес электронной почты) архивы списка python перестраиваются, и идентификаторы электронных писем меняются, что нарушает эти ссылки. В наши дни администраторы pydotorg обычно стараются избегать этого. - person Martijn Pieters; 19.08.2012
comment
Но с помощью .keys() можно получить список ключей. Настоящая хеш-таблица не будет хранить ключи, а только хэши для экономии места. - person noɥʇʎԀʎzɐɹƆ; 11.05.2016
comment
Более полное описание реализации python dict здесь: laurentluce.com/posts/python-dictionary- реализация - person Daniel Goldfarb; 18.07.2017
comment
@noɥʇʎԀʎzɐɹƆ - сам ключ не сохраняется, только ссылка на него и хэш. - person nosklo; 17.07.2020

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

>>> 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

Возможно, есть еще один уровень поиска помимо hash(), который позволяет избежать коллизий между ключами словаря. Или, может быть, dict() использует другой хэш.

(Кстати, это в Python 2.7.10. Та же история в Python 3.4.3 и 3.5.0 с коллизией на hash(1.1) == hash(214748749.8).)

person Bob Stein    schedule 01.11.2015
comment
Так что столкновений не избежать. Набор S может содержать бесконечно большое количество элементов, и вы хотите, чтобы он хэшировался до числа, которое может хранить компьютер. Каждая используемая реализация хеш-таблицы разрешает конфликты, причем двумя наиболее распространенными методами являются: а) открытая адресация и б) цепочка. Тот факт, что он не использует идеальный хэш, не означает, что это не хеш-таблица. - person TurnipEntropy; 06.06.2017
comment
В общем, коллизии будут происходить, потому что существует бесконечное число возможных хешируемых значений и конечных хеш-кодов. Даже хеш-таблица должна каким-то образом обрабатывать коллизии. - person Yanfeng Liu; 11.02.2019
comment
@YanfengLiu Я считаю, что это те же самые моменты, которые сделал TurnipEntropy. - person Bob Stein; 11.02.2019
comment
В 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 кстати. - person Will Croxford; 11.06.2019
comment
Причина, по которой это не нарушает работу словаря, заключается в том, что внутри дублирующиеся значения реализуются с использованием связанного списка и хранятся вместе с указателем на ключ, из которого они были сгенерированы. - person TrancendentalObject; 12.02.2021

да. Внутри он реализован как открытое хеширование на основе примитивного полинома над Z/2 (источник).

person Ben Hoffstein    schedule 22.09.2008

Чтобы расширить объяснение nosklo:

a = {}
b = ['some', 'list']
a[b] = 'some' # this won't work
a[tuple(b)] = 'some' # this will, same as a['some', 'list']
person Jeremy Cantrell    schedule 22.09.2008