Заказаны ли словари в 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требует гораздо больше памяти, чем разреженный массив для хранения ints.
Вы можете увидеть полный разговор о 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]: новые реализации словаря обеспечивают лучшую память , будучи спроектированы более компактно; это главное преимущество здесь. С точки зрения скорости, разница не столь существенна, есть места, где новый дикт может привести к небольшим регрессиям ( например, поиск по ключевым словам), в то время как в других (на ум приходят итерации и изменение размеров) должно наблюдаться повышение производительности.
В целом производительность словаря, особенно в реальных ситуациях, улучшается благодаря введенной компактности.