Детали реализации python dict

У меня вопрос о реализации словаря python.

Похоже, что python будет поддерживать порядок поиска для всех ключей, например если вы выполните следующую операцию

a = {}
a[3] = 1
a[0] = 2

a = {0:2, 3:1}

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

Надеюсь, я поставил вопрос ясно.

Спасибо

Ответ 1

Порядок dict определяется полностью хеширующей функцией объекта (и порядком вставки, если есть хеш-коллизии). Целые хэши сами по себе (по крайней мере, до sys.maxint):

>>> hash(1)
1

Реализация python (C) принимает хэш-значение объекта и принимает несколько бит, чтобы определить индекс в таблице. Количество бит, которое требуется, зависит от длины словаря. По умолчанию у dict есть 8 доступных слотов, поэтому числа 0 и 8 будут сталкиваться. Мы можем видеть это следующим образом:

>>> d1 = {}
>>> d1[0] = 'foo'
>>> d1[8] = 'bar'
>>> d1
{0: 'foo', 8: 'bar'}
>>>
>>> d2 = {}
>>> d2[8] = 'bar'
>>> d2[0] = 'foo'
>>> d2
{8: 'bar', 0: 'foo'}

Так как 0 и 8 сталкиваются в нашем словаре, порядок вставки, как представляется, сохраняется. 0 занимает первый доступный слот (в конце концов, независимо от того, сколько бит вы берете с 0, вы получите 0). 8 пытается взять этот слот. Однако, если этот слот взят, разрешение конфликтов возникает, а python вставляет это значение в некоторый более поздний слот.

Конечно, если ваш словарь имеет более чем 5 элементов, он будет изменен (я думаю, до 16, но не цитирую меня), а 0 и 8 больше не будут сталкиваться...

>>> d1 = {x:x for x in range(1, 6)}
>>> d1[0] = 0
>>> d1[8] = 8
>>> d1
{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 8: 8}
>>> d2 = {x:x for x in range(1, 6)}
>>> d2[8] = 8
>>> d2[0] = 0
>>> d2
{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 8: 8}

Обратите внимание, что порядок сортировки сохраняется (не порядок вставки), что означает, что каждое целое число получило предпочтительное место в хеш-таблице (без коллизий). Я думаю, что размер бита изменяется, когда он равен 2/3rds.


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

Ответ 2

Упорядочение индекса Dict является следствием того, как реализуется dict, и на него нельзя положиться.

Чтобы быть точным, Python не изменяет ваш порядок вставки (так как это просто определено как порядок вставки элементов в dict), но порядок итераций не имеет гарантий.

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

Если вы хотите, чтобы порядок итераций был таким же, как и порядок вставки, посмотрите ordereddict.