Словари упорядочены в Python 3.6 (по крайней мере, под реализацию CPython) в отличие от предыдущих воплощений. Это кажется существенным изменением, но это только короткий параграф в документации . Он описывается как подробность реализации CPython, а не как языковая функция, но также подразумевает, что это может стать стандартом в будущем.
Как новая реализация словаря работает лучше, чем старая при сохранении порядка элементов?
Вот текст из документации:
dict()
теперь использует «компактное» представление, впервые разработанное PyPy . Использование памяти новой функцией dict () на 20-25% меньше по сравнению с Python 3.5. PEP 468 (сохранение порядка ** kwargs в функции.) Реализуется этим. Сохраняющий порядок аспект этой новой реализации считается деталью реализации, и на него не следует полагаться (это может измениться в будущем, но желательно иметь эту новую реализацию dict в языке в течение нескольких выпусков, прежде чем изменять спецификацию языка. предписывать семантику сохранения порядка для всех текущих и будущих реализаций Python, это также помогает сохранить обратную совместимость со старыми версиями языка, где все еще действует случайный порядок итераций, например, Python 3.5). (Предоставлено ИНАДА Наоки ввыпуск 27350 . Идея, изначально предложенная Раймондом Хеттингером .)
Обновление в декабре 2017 года: dict
сохранение порядка вставки гарантировано для Python 3.7
источник
**kwargs
и, как таковая, используемая формулировка является дипломатической:**kwargs
в сигнатуре функции теперь гарантированно отображается отображение, сохраняющее порядок вставки . Они использовали термин mapping , чтобы не заставлять никакие другие реализации делать упорядоченный dict (и использоватьOrderedDict
внутренне) и как способ показать, что это не должно зависеть от того факта, чтоdict
is не упорядочен.Ответы:
Они вставляются по порядку [1] . Начиная с Python 3.6, для реализации Python на CPython словари запоминают порядок вставленных элементов . Это считается деталью реализации в Python 3.6 ; вам нужно использовать,
OrderedDict
если вы хотите, чтобы порядок вставки был гарантирован для других реализаций Python (и другого упорядоченного поведения [1] ).Начиная с Python 3.7 , это больше не деталь реализации, а вместо этого становится языковой особенностью. Из сообщения Python-dev от GvR :
Это просто означает, что вы можете зависеть от этого . Другие реализации Python также должны предлагать упорядоченный словарь для вставки, если они хотят быть соответствующей реализацией Python 3.7.
По сути, сохраняя два массива .
Первый массив,
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 относительно этой функции, если вам интересно, это хорошее чтение.
В первоначальном предложении Рэймонда Хеттингера можно увидеть визуализацию используемых структур данных, которая отражает суть идеи.
Как вы можете видеть визуально, в исходном предложении много места практически пусто, чтобы уменьшить количество столкновений и ускорить поиск. С новым подходом вы уменьшаете объем требуемой памяти, перемещая разреженность там, где она действительно требуется, в индексах.
[1]: я говорю «вставка упорядочена», а не «упорядочена», так как при наличии OrderedDict «упорядоченный» предполагает дальнейшее поведение, которого не обеспечивает
dict
объект . OrderedDicts являются обратимыми, предоставляют чувствительные к порядку методы и, главным образом, предоставляют чувствительные к порядку тесты на равенство ( , ). В настоящее время не предлагается ни одно из этих поведений / методов.==
!=
dict
[2]: новые реализации словаря обеспечивают лучшую память , будучи спроектированы более компактно; это главное преимущество здесь. С точки зрения скорости, разница не столь существенна, есть места, где новый дикт может привести к небольшим регрессиям ( например, поиск по ключевым словам), в то время как в других (на ум приходят итерации и изменение размеров) должно наблюдаться повышение производительности.
В целом производительность словаря, особенно в реальных ситуациях, улучшается благодаря введенной компактности.
источник
entries
изменяется список? или пустое место сохраняется? или это время от времени сжимается?DKIX_DUMMY
значением,-2
а запись вentry
массиве заменяется наNULL
, когда при вставке новые значения добавляются в массив записей, пока не удалось различить, но довольно точно, когда индексы заполняются за2/3
порог, выполняется изменение размера. Это может привести к сокращению вместо роста, еслиDUMMY
существует много записей.d = {i:i for i in range(100)}
и.pop
все элементы без вставки, размер не изменится. Когда вы добавляете к нему снова,d[1] = 1
соответствующий размер вычисляется и размер дикта изменяется.dict
упорядоченности»,dict
не упорядочены в том смысле, в какомOrderedDict
они. Примечательной проблемой является равенство.dict
s имеют порядок, нечувствительный==
,OrderedDict
s имеют порядок, чувствительный. ДампыOrderedDict
и переходыdicts
на сравнение, чувствительные к порядку, могут привести к серьезным сбоям в старом коде. Я предполагаю, что единственное, что может измениться вOrderedDict
s, это его реализация.Ниже приводится ответ на первый вопрос:
Я думаю, что это предложение из документации на самом деле достаточно, чтобы ответить на ваш вопрос
dict
явно не является упорядоченной коллекцией, поэтому, если вы хотите оставаться последовательным и не полагаться на побочный эффект новой реализации, вам следует придерживатьсяOrderedDict
.Сделайте свой код будущим :)
Там есть дебаты о том, что здесь .
РЕДАКТИРОВАТЬ: Python 3.7 будет держать это как функцию увидеть
источник
Обновление: Гвидо ван Россум объявил в списке рассылки, что начиная
dict
с Python 3.7 во всех реализациях Python должен сохраняться порядок вставки.источник
move_to_end
метод, и его равенство чувствительно к порядку: docs.python.org/3/library/… . Смотрите примечание к ответу Джима Фасаракиса Хиллиарда.Я хотел добавить к обсуждению выше, но не имею репутации, чтобы комментировать.
Python 3.8 еще не совсем выпущен, но он даже будет включать
reversed()
функцию в словарях (исключая другое отличие отOrderedDict
.Я не вижу упоминаний об операторе равенства или других функциях,
OrderedDict
поэтому они не совсем одинаковы.источник