Telegram Group & Telegram Channel
Как реализован dict в интерпретаторе Python

Словарь (ассоциативный массив / хэш-таблица / dict) — это такая замечательная структура данных в Python, которая поддерживает обращение, вставку и удаление в среднем за константное время O(1).

Возьмем в качестве примера словарь, который отображает реальное имя человека в его игровой никнейм.

nickname = {
"Gena": "Машина",
"Ivan": 12,
"Vazgen": "Gorniy Orel 228"
}


Визуально очень похоже на JSON. Ключами выступают "Gena", "Ivan", значениями "Машина", 12 и тд. Причем последние могут быть чем угодно: объектами, числами, строками, списками, словарями.

Ключи же должны быть хэшируемыми типами данных — такими, у которых определен метод __hash__. Обычно эти объекты являются неизменяемыми. Т.е. tuple может выступать в качестве ключа, а list — нет. Хотя в пользовательских классах можно наворотить все что угодно.

Что происходит на уровне интерпретатора CPython при добавлении нового ключа? Например, мы выполнили строчку nickname["Dima"] = "Арчибальд Шпицен-Дроссель".

На уровне C есть просто два массива фиксированной длины: dk_indices — хранит индексы и dk_entries — хранит пары ключ-значение, плюс несколько вспомогательных полей с размером самого словаря, типами данных и тд.

При вставке для объекта "Dima" вызывается функция PyObject_Hash, которая залезает в PyTypeObject — структуру с основными свойствами объекта (в Python все есть объект) и находит там хэш-функцию unicode_hash (строки из примера под капотом unicode). Применяя ее к "Dima", получает некоторое большое по модулю число. Кстати, сложность хэширования O(k), но мы предполагаем, что длина ключей в среднем сильно меньше размера словаря k << n.

Чтобы найти слот для hash("Dima") в dk_indices, берется остаток от деления на длину dk_indices. Если соответствующая ячейка в массиве пуста, то в dk_entries добавляется пара ("Dima", "Арчибальд Шпицен-Дроссель"). Если же ячейка занята, это означает что произошла коллизия. В простейшем случае можно было бы хранить в dk_entries не просто ключ-значение, а связный список из ключей и значений. Тогда при коллизиях мы бы просто делали append в конец списка.

Но в CPython используется алгоритм сдвига с пертурбацией. В случае коллизии он вычисляет новый индекс по формуле
    perturb >>= PERTURB_SHIFT;
j = (5*j) + 1 + perturb;
use j % 2**i as the next table index;

И повторяет процедуру до тех пор, пока не найдет свободную ячейку.

Такие дела. Все вышеперечисленное не претендует на истину в последней инстанции. Там еще есть PyDictKeyEntry vs PyDictUnicodeEntry, 6000 строк реализации dictobject.c и куча прочих нюансов. Но основная идея такая, если я нигде не наврал. А если наврал, пишите замечания в комментариях!



group-telegram.com/savostyanov_dmitry/491
Create:
Last Update:

Как реализован dict в интерпретаторе Python

Словарь (ассоциативный массив / хэш-таблица / dict) — это такая замечательная структура данных в Python, которая поддерживает обращение, вставку и удаление в среднем за константное время O(1).

Возьмем в качестве примера словарь, который отображает реальное имя человека в его игровой никнейм.

nickname = {
"Gena": "Машина",
"Ivan": 12,
"Vazgen": "Gorniy Orel 228"
}


Визуально очень похоже на JSON. Ключами выступают "Gena", "Ivan", значениями "Машина", 12 и тд. Причем последние могут быть чем угодно: объектами, числами, строками, списками, словарями.

Ключи же должны быть хэшируемыми типами данных — такими, у которых определен метод __hash__. Обычно эти объекты являются неизменяемыми. Т.е. tuple может выступать в качестве ключа, а list — нет. Хотя в пользовательских классах можно наворотить все что угодно.

Что происходит на уровне интерпретатора CPython при добавлении нового ключа? Например, мы выполнили строчку nickname["Dima"] = "Арчибальд Шпицен-Дроссель".

На уровне C есть просто два массива фиксированной длины: dk_indices — хранит индексы и dk_entries — хранит пары ключ-значение, плюс несколько вспомогательных полей с размером самого словаря, типами данных и тд.

При вставке для объекта "Dima" вызывается функция PyObject_Hash, которая залезает в PyTypeObject — структуру с основными свойствами объекта (в Python все есть объект) и находит там хэш-функцию unicode_hash (строки из примера под капотом unicode). Применяя ее к "Dima", получает некоторое большое по модулю число. Кстати, сложность хэширования O(k), но мы предполагаем, что длина ключей в среднем сильно меньше размера словаря k << n.

Чтобы найти слот для hash("Dima") в dk_indices, берется остаток от деления на длину dk_indices. Если соответствующая ячейка в массиве пуста, то в dk_entries добавляется пара ("Dima", "Арчибальд Шпицен-Дроссель"). Если же ячейка занята, это означает что произошла коллизия. В простейшем случае можно было бы хранить в dk_entries не просто ключ-значение, а связный список из ключей и значений. Тогда при коллизиях мы бы просто делали append в конец списка.

Но в CPython используется алгоритм сдвига с пертурбацией. В случае коллизии он вычисляет новый индекс по формуле
    perturb >>= PERTURB_SHIFT;
j = (5*j) + 1 + perturb;
use j % 2**i as the next table index;

И повторяет процедуру до тех пор, пока не найдет свободную ячейку.

Такие дела. Все вышеперечисленное не претендует на истину в последней инстанции. Там еще есть PyDictKeyEntry vs PyDictUnicodeEntry, 6000 строк реализации dictobject.c и куча прочих нюансов. Но основная идея такая, если я нигде не наврал. А если наврал, пишите замечания в комментариях!

BY Дмитрий Савостьянов Вещает


Warning: Undefined variable $i in /var/www/group-telegram/post.php on line 260

Share with your friend now:
group-telegram.com/savostyanov_dmitry/491

View MORE
Open in Telegram


Telegram | DID YOU KNOW?

Date: |

"We're seeing really dramatic moves, and it's all really tied to Ukraine right now, and in a secondary way, in terms of interest rates," Octavio Marenzi, CEO of Opimas, told Yahoo Finance Live on Thursday. "This war in Ukraine is going to give the Fed the ammunition, the cover that it needs, to not raise interest rates too quickly. And I think Jay Powell is a very tepid sort of inflation fighter and he's not going to do as much as he needs to do to get that under control. And this seems like an excuse to kick the can further down the road still and not do too much too soon." The company maintains that it cannot act against individual or group chats, which are “private amongst their participants,” but it will respond to requests in relation to sticker sets, channels and bots which are publicly available. During the invasion of Ukraine, Pavel Durov has wrestled with this issue a lot more prominently than he has before. Channels like Donbass Insider and Bellum Acta, as reported by Foreign Policy, started pumping out pro-Russian propaganda as the invasion began. So much so that the Ukrainian National Security and Defense Council issued a statement labeling which accounts are Russian-backed. Ukrainian officials, in potential violation of the Geneva Convention, have shared imagery of dead and captured Russian soldiers on the platform. During the operations, Sebi officials seized various records and documents, including 34 mobile phones, six laptops, four desktops, four tablets, two hard drive disks and one pen drive from the custody of these persons. You may recall that, back when Facebook started changing WhatsApp’s terms of service, a number of news outlets reported on, and even recommended, switching to Telegram. Pavel Durov even said that users should delete WhatsApp “unless you are cool with all of your photos and messages becoming public one day.” But Telegram can’t be described as a more-secure version of WhatsApp. "The inflation fire was already hot and now with war-driven inflation added to the mix, it will grow even hotter, setting off a scramble by the world’s central banks to pull back their stimulus earlier than expected," Chris Rupkey, chief economist at FWDBONDS, wrote in an email. "A spike in inflation rates has preceded economic recessions historically and this time prices have soared to levels that once again pose a threat to growth."
from ms


Telegram Дмитрий Савостьянов Вещает
FROM American