Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Dictionary in Python
Search
Cyril Lashkevich
March 13, 2014
Programming
0
99
Dictionary in Python
Cyril Lashkevich
March 13, 2014
Tweet
Share
More Decks by Cyril Lashkevich
See All by Cyril Lashkevich
Go Scheduler
notorca
2
560
Bitcode in Swift
notorca
0
40
Mobile Optimized 2014
notorca
1
250
Fun with blocks in ObjC
notorca
1
79
CocoaHeads in Grodno, Lighting
notorca
0
71
Foundation data structures
notorca
0
130
iOS memory management
notorca
0
78
NSProxy, multithreading, messaging
notorca
1
82
Python impergections
notorca
0
62
Other Decks in Programming
See All in Programming
Ruby on cygwin 2025-02
fd0
0
140
Grafana Loki によるサーバログのコスト削減
mot_techtalk
1
130
CI改善もDatadogとともに
taumu
0
120
もう僕は OpenAPI を書きたくない
sgash708
5
1.6k
お前もAI鬼にならないか?👹Bolt & Cursor & Supabase & Vercelで人間をやめるぞ、ジョジョー!👺
taishiyade
6
4k
SpringBoot3.4の構造化ログ #kanjava
irof
2
990
個人アプリを2年ぶりにアプデしたから褒めて / I just updated my personal app, praise me!
lovee
0
340
『GO』アプリ データ基盤のログ収集システムコスト削減
mot_techtalk
0
120
メンテが命: PHPフレームワークのコンテナ化とアップグレード戦略
shunta27
0
120
GAEログのコスト削減
mot_techtalk
0
120
ARA Ansible for the teams
kksat
0
150
XStateを用いた堅牢なReact Components設計~複雑なClient Stateをシンプルに~ @React Tokyo ミートアップ #2
kfurusho
1
900
Featured
See All Featured
Side Projects
sachag
452
42k
A better future with KSS
kneath
238
17k
How to Think Like a Performance Engineer
csswizardry
22
1.3k
Building Flexible Design Systems
yeseniaperezcruz
328
38k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
129
19k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
9
440
YesSQL, Process and Tooling at Scale
rocio
172
14k
Rebuilding a faster, lazier Slack
samanthasiow
80
8.8k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
Transcript
Dictionary в Python По мотивам Objects/dictnotes.txt Cyril @notorca Lashkevich piątek,
30 sierpnia 13
Как создать словарь {} dict() PyObject* PyDict_New() piątek, 30 sierpnia
13
Сколько словарей в Hello World? $ python -c "print('Hello world')"
| wc -l piątek, 30 sierpnia 13
Сколько словарей в Hello World? $ python -c "print('Hello world')"
| wc -l 1642 piątek, 30 sierpnia 13
Именованные параметры функицй 1 запись, 1 чтение 1-3 элемента Часто
встречается в обычных программах на Python piątek, 30 sierpnia 13
Поиск метода в классе 1 запись, много чтений 8-16 элементов
При наследовании много неудачных чтений с последующим поиском в базовом классе piątek, 30 sierpnia 13
Атрибуты и глобальные пременные Много записей и чтений 4-10 элементов
piątek, 30 sierpnia 13
Builtins Частые чтение, почти не бывает записи ~150 строковых ключей
(3.3) По некоторым ключам чтения гораздо чаще чем по другим piątek, 30 sierpnia 13
Удаление повторов, подсчет элементов Одинократное чтение по каждому из ключей
Произвольное количество элементов Многократный доступ по одному ключу подряд piątek, 30 sierpnia 13
Удаление дубликатов dict.fromkeys(seqn).keys() Все операции записи при конструировании piątek, 30
sierpnia 13
Подсчет элементов в последовательности for e in seqn: d[e] =
d.get(e,0) + 1 2 последовательных доступа по одинаковому ключу piątek, 30 sierpnia 13
Создание индекса из словаря списков setdefault совмещает 2 поиска в
1м for pnum, page in enumerate(pages): for w in page: d.setdefault(w, []).append(pnum) piątek, 30 sierpnia 13
Проверка принадлежности Словари произвольных размеров Создаются 1 раз и затем
мало изменяются Много вызовов has_key() и __contains__() piątek, 30 sierpnia 13
Динамические отображения Чередующиеся добавления, удаления, чтение и перезапись элементов piątek,
30 sierpnia 13
Реализация (2.7) Последовательная область памяти с доступом по индксу typedef
struct { Py_hash_t me_hash; PyObject *me_key; PyObject *me_value; } PyDictKeyEntry; piątek, 30 sierpnia 13
Пустой dict с размером по умолчанию (8 элементов) >>> d
= {} piątek, 30 sierpnia 13
Хеширование ключа Ключ преобразуется в индекс с помощъю функции hash()
hash() возвращает 32/64bit значение Для индекса берется n младших бит piątek, 30 sierpnia 13
Свойства хеша Для равных значений хеши всегда равны Даже если
представление значений разное: 9, 9.0, complex(9,0) Похожие значения дают сильно отличающиеся хеши piątek, 30 sierpnia 13
>>> d['ftp'] = 21 >>> bits(hash('ftp'))[-8:] 10100001 piątek, 30 sierpnia
13
>>> d['ftp'] = 21 >>> bits(hash('ftp'))[-8:] 10100001 piątek, 30 sierpnia
13
>>> d['ssh'] = 22 >>> bits(hash('ssh'))[-3:] 101 piątek, 30 sierpnia
13
>>> d['ssh'] = 22 >>> bits(hash('ssh'))[-3:] 101 piątek, 30 sierpnia
13
>>> d['smtp'] = 25 >>> bits(hash('smtp'))[-3:] 100 piątek, 30 sierpnia
13
>>> d['smtp'] = 25 >>> bits(hash('smtp'))[-3:] 100 piątek, 30 sierpnia
13
>>> d['time'] = 37 >>> bits(hash('time'))[-3:] 111 piątek, 30 sierpnia
13
>>> d['time'] = 37 >>> bits(hash('time'))[-3:] 111 piątek, 30 sierpnia
13
>>> d['www'] = 80 >>> bits(hash('www'))[-3:] 010 piątek, 30 sierpnia
13
>>> d['www'] = 80 >>> bits(hash('www'))[-3:] 010 piątek, 30 sierpnia
13
d = {'ftp': 21, 'ssh': 22, 'smtp': 25, 'time': 37,
'www': 80} piątek, 30 sierpnia 13
Поиск в словаре Вычислить хеш от ключа Обрезать старшие биты
Взять значение из слота по индексу piątek, 30 sierpnia 13
>>> d['smtp'] 25 >>> bits(hash('smtp'))[-3:] 100 piątek, 30 sierpnia 13
Перебор всех элементов Словари возвращают свои ключи или значения в
порядке отличном от порядка добавления piątek, 30 sierpnia 13
>>> print d {'ftp': 21, 'www': 80, 'smtp': 25, 'ssh':
22, 'time': 37} piątek, 30 sierpnia 13
>>> d.keys() ['ftp', 'www', 'smtp', 'ssh', 'time'] piątek, 30 sierpnia
13
>>> d.values() [21, 80, 25, 22, 37] piątek, 30 sierpnia
13
Коллизии Разные ключи пытаются доступиться по одинаковому индексу Находим первое
свободное место piątek, 30 sierpnia 13
>>> d = {} piątek, 30 sierpnia 13
>>> d['smtp'] = 21 piątek, 30 sierpnia 13
>>> d['smtp'] = 21 piątek, 30 sierpnia 13
>>> d['dict'] = 2628 piątek, 30 sierpnia 13
>>> d['dict'] = 2628 piątek, 30 sierpnia 13
>>> d['svn'] = 3690 piątek, 30 sierpnia 13
>>> d['svn'] = 3690 piątek, 30 sierpnia 13
>>> d['ircd'] = 6667 piątek, 30 sierpnia 13
>>> d['ircd'] = 6667 piątek, 30 sierpnia 13
>>> d['zope'] = 9673 piątek, 30 sierpnia 13
>>> d['zope'] = 9673 # 2 из 5ти элементов на
своих ожидаемых местах piątek, 30 sierpnia 13
Коллизии и очередность Поскольку из за коллизий элементы могут находится
не по своим "естественным" индексам порядок элементов зависит от порядка добавления piątek, 30 sierpnia 13
Поиск первой свободной ячейки Последовательный поиск плох для int ключей
pertrurb = hash while (<слот занят>) { slot = (5*slot) + 1 + perturb; perturb >>= 5; } piątek, 30 sierpnia 13
>>> d['svn'] 3690 piątek, 30 sierpnia 13
>>> d['ircd'] 6667 piątek, 30 sierpnia 13
>>> d['nsca'] KeyError: 'nsca' piątek, 30 sierpnia 13
>>> d['netstat'] KeyError: 'netstat' piątek, 30 sierpnia 13
Не все поиски одинаковы Некоторые находят результат сразу Некоторым нужны
несколько итераций piątek, 30 sierpnia 13
threes = {3: 1, 3+8: 2, 3+16: 3, 3+24: 4,
3+32: 5} piątek, 30 sierpnia 13
Удаление элементов Нелзя просто так взять, и пометить ячейку как
пустую Необходимо вставить специальный "dummy" элемент piątek, 30 sierpnia 13
del d['smtp'] piątek, 30 sierpnia 13
del d['smtp'] d['ircd'] ??? piątek, 30 sierpnia 13
del d['smtp'] #Заменяем на "dummy" слот #Может быть использован снова
piątek, 30 sierpnia 13
del d['smtp'] #Заменяем на "dummy" слот #Может быть использован снова
piątek, 30 sierpnia 13
>>> del d['svn'], d['dict'], d['zope'] >>> d['ircd'] piątek, 30 sierpnia
13
Увеличение размера таблицы Таблица заполнена максимум на 2/3 2.7: <
50k size × 4 > 50k size × 2 3.3: size × 2 piątek, 30 sierpnia 13
>>> d = {} piątek, 30 sierpnia 13
d = dict.fromkeys(words[:5]) # 40% коллизий # Заполнен на ⅔,
resize piątek, 30 sierpnia 13
d['abash'] = None # размер ×4 до 32 # 0%
коллизий piątek, 30 sierpnia 13
d = dict.fromkeys(words[:21]) # 29% коллизий # Заполнен на ⅔
piątek, 30 sierpnia 13
d['abode'] = None # размер ×4 до 128 # 9%
коллизий piątek, 30 sierpnia 13
d = dict.fromkeys(words[:85]) # 33% коллизий # Заполнен на ⅔
piątek, 30 sierpnia 13
Время доступа к элементам Растет по мере заполнения словаря Затем
резко умешьшается после изменения размера Среднее время доступа ОК piątek, 30 sierpnia 13
Поиски vs размер piątek, 30 sierpnia 13
Время vs размер piątek, 30 sierpnia 13
Удаление элементов Не уменьшает размер таблицы Таблица может уменьшиться только
при добавлении элементов piątek, 30 sierpnia 13
Порядок элементов Во время изменения размера порядок элементов может полностью
поменяться Добавление элементов во время итерации запрещено RuntimeError: dictionary changed size during iteration piątek, 30 sierpnia 13
Свой __hash__() Хорошо перемешать биты Равные хеши для равных элементов
__eq__() должен быть Быстро вычисляется piątek, 30 sierpnia 13
Пример __hash__() class Point(object): def __init__(self, x, y): self.x, self.y
= x, y def __eq__(self, p): return self.x==p.x and self.y==p.y def __hash__(self): return hash(self.x) ^ hash(self.y) piątek, 30 sierpnia 13
oCERT #2011-003 Хэш для str, bytes и datetime смешивается с
"солью" уникальной для каждого процесса Python pre 3.3: -R option 3.3: by default piątek, 30 sierpnia 13
Python 3: Split-table словари. Общая таблица с ключами для разных
таблиц со значениями piątek, 30 sierpnia 13
Спасибо http://blip.tv/pycon-us- videos-2009-2010-2011/pycon-2010- the-mighty-dictionary-55-3352147 Python source code piątek, 30 sierpnia
13