Заказаны ли словари в Python 3.6+?
Они вставляются по порядку [1] . Начиная с Python 3.6, для реализации Python на CPython словари запоминают порядок вставленных элементов . Это считается деталью реализации в Python 3.6 ; вам нужно использовать, OrderedDict
если вы хотите, чтобы порядок вставки был гарантирован для других реализаций Python (и другого упорядоченного поведения [1] ).
Начиная с Python 3.7 , это больше не деталь реализации, а вместо этого становится языковой особенностью. Из сообщения Python-dev от GvR :
Сделай это так. «Dict сохраняет порядок вставки» - это решение. Спасибо!
Это просто означает, что вы можете зависеть от этого . Другие реализации Python также должны предлагать упорядоченный словарь для вставки, если они хотят быть соответствующей реализацией Python 3.7.
Как 3.6
реализация словаря Python работает лучше [2], чем старая, при сохранении порядка элементов?
По сути, сохраняя два массива .
Первый массив, dk_entries
содержит записи ( типаPyDictKeyEntry
) для словаря в том порядке, в котором они были вставлены. Порядок сохранения достигается за счет того, что он является массивом только для добавления, где новые элементы всегда вставляются в конце (порядок вставки).
Второй, dk_indices
содержит индексы для dk_entries
массива (то есть значения, которые указывают на позицию соответствующей записи в dk_entries
). Этот массив действует как хеш-таблица. Когда ключ хэшируется, это приводит к одному из индексов, сохраненных в, dk_indices
и соответствующая запись выбирается посредством индексации dk_entries
. Поскольку сохраняются только индексы, тип этого массива зависит от общего размера словаря (в диапазоне от типа int8_t
( 1
байт) до int32_t
/ int64_t
( 4
/ 8
байт) в 32
/ 64
битных сборках)
В предыдущей реализации должен был размещаться разреженный массив типа PyDictKeyEntry
и размера dk_size
; к сожалению, это также привело к большому количеству пустого пространства, так как этот массив не мог быть 2/3 * dk_size
переполнен по соображениям производительности . (и пустое пространство все еще имело PyDictKeyEntry
размер!).
Сейчас это не так, поскольку сохраняются только необходимые записи (те, которые были вставлены) и сохраняется разреженный массив типа intX_t
(в X
зависимости от размера dict) 2/3 * dk_size
. Пустое пространство изменено с типа PyDictKeyEntry
на intX_t
.
Итак, очевидно, что создание разреженного массива типа PyDictKeyEntry
требует гораздо больше памяти, чем разреженный массив для хранения int
s.
Вы можете увидеть полный разговор о Python-Dev относительно этой функции, если вам интересно, это хорошее чтение.
В первоначальном предложении Рэймонда Хеттингера можно увидеть визуализацию используемых структур данных, которая отражает суть идеи.
Например, словарь:
d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
в настоящее время хранится как [keyhash, key, value]:
entries = [['--', '--', '--'],
[-8522787127447073495, 'barry', 'green'],
['--', '--', '--'],
['--', '--', '--'],
['--', '--', '--'],
[-9092791511155847987, 'timmy', 'red'],
['--', '--', '--'],
[-6480567542315338377, 'guido', 'blue']]
Вместо этого данные должны быть организованы следующим образом:
indices = [None, 1, None, None, None, 0, None, 2]
entries = [[-9092791511155847987, 'timmy', 'red'],
[-8522787127447073495, 'barry', 'green'],
[-6480567542315338377, 'guido', 'blue']]
Как вы можете видеть визуально, в исходном предложении много места практически пусто, чтобы уменьшить количество столкновений и ускорить поиск. С новым подходом вы уменьшаете объем требуемой памяти, перемещая разреженность там, где она действительно требуется, в индексах.
[1]: я говорю «вставка упорядочена», а не «упорядочена», так как при наличии OrderedDict «упорядоченный» предполагает дальнейшее поведение, которого не обеспечиваетdict
объект . OrderedDicts являются обратимыми, предоставляют чувствительные к порядку методы и, главным образом, предоставляют чувствительные к порядку тесты на равенство ( , ). В настоящее время не предлагается ни одно из этих поведений / методов.
==
!=
dict
[2]: новые реализации словаря обеспечивают лучшую память , будучи спроектированы более компактно; это главное преимущество здесь. С точки зрения скорости, разница не столь существенна, есть места, где новый дикт может привести к небольшим регрессиям ( например, поиск по ключевым словам), в то время как в других (на ум приходят итерации и изменение размеров) должно наблюдаться повышение производительности.
В целом производительность словаря, особенно в реальных ситуациях, улучшается благодаря введенной компактности.