Словарь это очень распространённый тип данных в Python.
Он присутствует буквально в каждом скрипте.
Именованные аргументы (kwargs), атрибуты объекта (ˍˍdictˍˍ), любые неймспейсы и тд.
Одна из основных особенностей словаря была в том, что это неупорядоченное множество. То есть порядок добавления ключей не гарантирует что они сохранятся в той же последовательности. Но всё изменилось в Python3.6. Как это произошло?
Словарь, как часто используемый тип данных, стараются максимально оптимизировать. Про одну из таких оптимизация нам рассказывает PEP468 - Preserving the order of **kwargs in a function.
Хм, причем здесь оптимизация?
Всё начинается с отдельной имплементации Python под названием PyPy. В этой версии интерпретатора сделали довольно хорошую оптимизацию словарю.
Показательно разница описана на этой странице
Если вкратце, то дело вот в чём.
Словарь на стороне С это массив. Каждый элемент это тоже массив из 3х элементов (хеш ключа, ключ и значение).
Раньше, чтобы всякий раз при обновлении словаря не изменять размер массива в С (это затратно по времени), изначально он делался с запасом. Как только массив заполняется, его еще увеличивают с запасом, обычно на 1/3. При этом элементы, еще не занятые данными, заполнялись пустышками (полный пример на странице по ссылке выше)
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']]
Именно этот принцип повторили в Python 3.6. Что мы получаем в итоге?
🔸 Увеличилась скорость поиска и добавления ключей.
🔸 Сократился расход памяти в 3 раза
Python 2.x-3.5
>>> d = {x: x*2 for x in range(100)}
>>> d.ˍˍsizeofˍˍ()
12536
Python 3.6
>>> d = {x: x*2 for x in range(100)}
>>> d.ˍˍsizeofˍˍ()
4680
Ведь теперь вместо элемента ['--', '--', '--'] у нас просто None, который, кстати, является одним и тем же объектом где бы он не использовался.
🔸 Как бонус (или как побочный эффект), мы получаем упорядоченность ключей.
То есть одним выстрелом завалили трёх мамонтов!
#pep