Ответ 1
Являются ли словари упорядоченными в 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.
Как реализуется реализация словаря Python
3.6
лучше [2] чем предыдущая, сохраняя порядок элементов?
По существу, сохраняя два массива.
-
Первый массив,
dk_entries
, содержит записи (типаPyDictKeyEntry
) для словаря в том порядке, в котором они были вставлены. Сохранение порядка достигается тем, что это добавляет только массив, в котором новые элементы всегда вставлены в конце (порядок вставки). -
Второй,
dk_indices
содержит индексы для массиваdk_entries
(то есть значения, указывающие позицию соответствующей записи вdk_entries
). Этот массив действует как хеш-таблица. Когда ключ хэшируется, он приводит к одному из индексов, хранящихся вdk_indices
, и соответствующая запись извлекается индексированиемdk_entries
. Поскольку сохраняются только индексы, тип этого массива зависит от общего размера словаря (отint8_t
(1
byte ) наint32_t
/int64_t
(/8
байты) в битовых строках32
/64
)
В предыдущей реализации должен был быть выделен разреженный массив типа PyDictKeyEntry
и размер dk_size
; к сожалению, это также привело к большому количеству пустого пространства, так как для производительности не хватило больше 2/3 * dk_size
по причинам производительности. (а пустое пространство по-прежнему имело размер PyDictKeyEntry
!).
Теперь это не так, поскольку хранятся только необходимые записи (те, которые были вставлены), и разреженный массив типа intX_t
(X
в зависимости от размера dict) 2/3 * dk_size
full. Пустое пространство изменилось с типа PyDictKeyEntry
на intX_t
.
Итак, очевидно, что создание разреженного массива типа PyDictKeyEntry
гораздо более требовательнее к памяти, чем разреженный массив для хранения int
s.
Вы можете увидеть полный диалог на Python-Dev относительно этой функции, если это интересно, это хорошее чтение.
В оригинальном предложении, сделанном Раймондом Хеттингером, можно увидеть визуализацию используемых структур данных, которая отражает суть идеи.
Например, словарь:
d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}
в настоящее время хранится как:
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]: Новые реализации словарей лучше выполняют память, будучи более компактными; что основное преимущество здесь. Скорость мудрая, разница не настолько резкая, там места, где новый dict может ввести небольшие регрессии (ключевые поисковые запросы, например), в то время как в других (итерация и изменение размера приходят на ум) должно быть повышение производительности. Суб >
<суб > В целом, производительность словаря, особенно в реальных ситуациях, улучшается благодаря введенной компактности.
Суб >