Dictionary в Python. По мотивам Objects/dictnotes.txt

78
Dictionary в Python По мотивам Objects/dictnotes.txt Cyril @notorca Lashkevich piątek, 30 sierpnia 13

description

Dictionary в Python. По мотивам Objects/dictnotes.txt Автор: Кирилл Лашкевич (Viber)

Transcript of Dictionary в Python. По мотивам Objects/dictnotes.txt

Page 1: Dictionary в Python. По мотивам Objects/dictnotes.txt

Dictionary в PythonПо мотивам Objects/dictnotes.txt

Cyril @notorca Lashkevich

piątek, 30 sierpnia 13

Page 2: Dictionary в Python. По мотивам Objects/dictnotes.txt

Как создать словарь

{}

dict()

PyObject* PyDict_New()

piątek, 30 sierpnia 13

Page 3: Dictionary в Python. По мотивам Objects/dictnotes.txt

Сколько словарей в Hello World?

$ python -c "print('Hello world')" | wc -l

piątek, 30 sierpnia 13

Page 4: Dictionary в Python. По мотивам Objects/dictnotes.txt

Сколько словарей в Hello World?

$ python -c "print('Hello world')" | wc -l

1642

piątek, 30 sierpnia 13

Page 5: Dictionary в Python. По мотивам Objects/dictnotes.txt

Именованные параметры функицй

1 запись, 1 чтение

1-3 элемента

Часто встречается в обычных программах на Python

piątek, 30 sierpnia 13

Page 6: Dictionary в Python. По мотивам Objects/dictnotes.txt

Поиск метода в классе

1 запись, много чтений

8-16 элементов

При наследовании много неудачных чтений с последующим поиском в базовом классе

piątek, 30 sierpnia 13

Page 7: Dictionary в Python. По мотивам Objects/dictnotes.txt

Атрибуты и глобальные пременные

Много записей и чтений

4-10 элементов

piątek, 30 sierpnia 13

Page 8: Dictionary в Python. По мотивам Objects/dictnotes.txt

Builtins

Частые чтение, почти не бывает записи

~150 строковых ключей (3.3)

По некоторым ключам чтения гораздо чаще чем по другим

piątek, 30 sierpnia 13

Page 9: Dictionary в Python. По мотивам Objects/dictnotes.txt

Удаление повторов,подсчет элементов

Одинократное чтение по каждому из ключей

Произвольное количество элементов

Многократный доступ по одному ключу подряд

piątek, 30 sierpnia 13

Page 10: Dictionary в Python. По мотивам Objects/dictnotes.txt

Удаление дубликатов

dict.fromkeys(seqn).keys()

Все операции записи при конструировании

piątek, 30 sierpnia 13

Page 11: Dictionary в Python. По мотивам Objects/dictnotes.txt

Подсчет элементов в последовательности

for e in seqn: d[e] = d.get(e,0) + 1

2 последовательных доступа по одинаковому ключу

piątek, 30 sierpnia 13

Page 12: Dictionary в Python. По мотивам Objects/dictnotes.txt

Создание индекса из словаря списков

setdefault совмещает 2 поиска в 1м

for pnum, page in enumerate(pages): for w in page: d.setdefault(w, []).append(pnum)

piątek, 30 sierpnia 13

Page 13: Dictionary в Python. По мотивам Objects/dictnotes.txt

Проверка принадлежности

Словари произвольных размеров

Создаются 1 раз и затем мало изменяются

Много вызовов has_key() и __contains__()

piątek, 30 sierpnia 13

Page 14: Dictionary в Python. По мотивам Objects/dictnotes.txt

Динамические отображения

Чередующиеся добавления, удаления, чтение и перезапись элементов

piątek, 30 sierpnia 13

Page 15: Dictionary в Python. По мотивам Objects/dictnotes.txt

Реализация (2.7)

Последовательная область памяти с доступом по индксу

typedef struct { Py_hash_t me_hash; PyObject *me_key; PyObject *me_value;} PyDictKeyEntry;

piątek, 30 sierpnia 13

Page 16: Dictionary в Python. По мотивам Objects/dictnotes.txt

Пустой dict с размером по умолчанию (8 элементов)

>>> d = {}

piątek, 30 sierpnia 13

Page 17: Dictionary в Python. По мотивам Objects/dictnotes.txt

Хеширование ключа

Ключ преобразуется в индекс с помощъю функции hash()

hash() возвращает 32/64bit значение

Для индекса берется n младших бит

piątek, 30 sierpnia 13

Page 18: Dictionary в Python. По мотивам Objects/dictnotes.txt

Свойства хеша

Для равных значений хеши всегда равны

Даже если представление значений разное: 9, 9.0, complex(9,0)

Похожие значения дают сильно отличающиеся хеши

piątek, 30 sierpnia 13

Page 19: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['ftp'] = 21>>> bits(hash('ftp'))[-8:]10100001

piątek, 30 sierpnia 13

Page 20: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['ftp'] = 21>>> bits(hash('ftp'))[-8:]10100001

piątek, 30 sierpnia 13

Page 21: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['ssh'] = 22>>> bits(hash('ssh'))[-3:]101

piątek, 30 sierpnia 13

Page 22: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['ssh'] = 22>>> bits(hash('ssh'))[-3:]101

piątek, 30 sierpnia 13

Page 23: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['smtp'] = 25>>> bits(hash('smtp'))[-3:]100

piątek, 30 sierpnia 13

Page 24: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['smtp'] = 25>>> bits(hash('smtp'))[-3:]100

piątek, 30 sierpnia 13

Page 25: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['time'] = 37>>> bits(hash('time'))[-3:]111

piątek, 30 sierpnia 13

Page 26: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['time'] = 37>>> bits(hash('time'))[-3:]111

piątek, 30 sierpnia 13

Page 27: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['www'] = 80>>> bits(hash('www'))[-3:]010

piątek, 30 sierpnia 13

Page 28: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['www'] = 80>>> bits(hash('www'))[-3:]010

piątek, 30 sierpnia 13

Page 29: Dictionary в Python. По мотивам Objects/dictnotes.txt

d = {'ftp': 21, 'ssh': 22, 'smtp': 25, 'time': 37, 'www': 80}

piątek, 30 sierpnia 13

Page 30: Dictionary в Python. По мотивам Objects/dictnotes.txt

Поиск в словаре

Вычислить хеш от ключа

Обрезать старшие биты

Взять значение из слота по индексу

piątek, 30 sierpnia 13

Page 31: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['smtp']25>>> bits(hash('smtp'))[-3:]100

piątek, 30 sierpnia 13

Page 32: Dictionary в Python. По мотивам Objects/dictnotes.txt

Перебор всех элементов

Словари возвращают свои ключи или значения в порядке отличном от порядка добавления

piątek, 30 sierpnia 13

Page 33: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> print d{'ftp': 21, 'www': 80, 'smtp': 25, 'ssh': 22, 'time': 37}

piątek, 30 sierpnia 13

Page 34: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d.keys()['ftp', 'www', 'smtp', 'ssh', 'time']

piątek, 30 sierpnia 13

Page 35: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d.values()[21, 80, 25, 22, 37]

piątek, 30 sierpnia 13

Page 36: Dictionary в Python. По мотивам Objects/dictnotes.txt

Коллизии

Разные ключи пытаются доступиться по одинаковому индексу

Находим первое свободное место

piątek, 30 sierpnia 13

Page 37: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d = {}

piątek, 30 sierpnia 13

Page 38: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['smtp'] = 21

piątek, 30 sierpnia 13

Page 39: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['smtp'] = 21

piątek, 30 sierpnia 13

Page 40: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['dict'] = 2628

piątek, 30 sierpnia 13

Page 41: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['dict'] = 2628

piątek, 30 sierpnia 13

Page 42: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['svn'] = 3690

piątek, 30 sierpnia 13

Page 43: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['svn'] = 3690

piątek, 30 sierpnia 13

Page 44: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['ircd'] = 6667

piątek, 30 sierpnia 13

Page 45: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['ircd'] = 6667

piątek, 30 sierpnia 13

Page 46: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['zope'] = 9673

piątek, 30 sierpnia 13

Page 47: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['zope'] = 9673# 2 из 5ти элементов на своих ожидаемых местах

piątek, 30 sierpnia 13

Page 48: Dictionary в Python. По мотивам Objects/dictnotes.txt

Коллизии и очередность

Поскольку из за коллизий элементы могут находится не по своим "естественным" индексам порядок элементов зависит от порядка добавления

piątek, 30 sierpnia 13

Page 49: Dictionary в Python. По мотивам Objects/dictnotes.txt

Поиск первой свободной ячейки

Последовательный поиск плох для int ключей

pertrurb = hashwhile (<слот занят>) { slot = (5*slot) + 1 + perturb; perturb >>= 5;}

piątek, 30 sierpnia 13

Page 50: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['svn']3690

piątek, 30 sierpnia 13

Page 51: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['ircd']6667

piątek, 30 sierpnia 13

Page 52: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['nsca']KeyError: 'nsca'

piątek, 30 sierpnia 13

Page 53: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d['netstat']KeyError: 'netstat'

piątek, 30 sierpnia 13

Page 54: Dictionary в Python. По мотивам Objects/dictnotes.txt

Не все поиски одинаковы

Некоторые находят результат сразу

Некоторым нужны несколько итераций

piątek, 30 sierpnia 13

Page 55: Dictionary в Python. По мотивам Objects/dictnotes.txt

threes = {3: 1, 3+8: 2, 3+16: 3, 3+24: 4, 3+32: 5}

piątek, 30 sierpnia 13

Page 56: Dictionary в Python. По мотивам Objects/dictnotes.txt

Удаление элементов

Нелзя просто так взять, и пометить ячейку как пустую

Необходимо вставить специальный "dummy" элемент

piątek, 30 sierpnia 13

Page 57: Dictionary в Python. По мотивам Objects/dictnotes.txt

del d['smtp']

piątek, 30 sierpnia 13

Page 58: Dictionary в Python. По мотивам Objects/dictnotes.txt

del d['smtp']d['ircd'] ???

piątek, 30 sierpnia 13

Page 59: Dictionary в Python. По мотивам Objects/dictnotes.txt

del d['smtp']#Заменяем на "dummy" слот#Может быть использован снова

piątek, 30 sierpnia 13

Page 60: Dictionary в Python. По мотивам Objects/dictnotes.txt

del d['smtp']#Заменяем на "dummy" слот#Может быть использован снова

piątek, 30 sierpnia 13

Page 61: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> del d['svn'], d['dict'], d['zope']>>> d['ircd']

piątek, 30 sierpnia 13

Page 62: Dictionary в Python. По мотивам Objects/dictnotes.txt

Увеличение размера таблицы

Таблица заполнена максимум на 2/3

2.7: < 50k size × 4 > 50k size × 2

3.3: size × 2

piątek, 30 sierpnia 13

Page 63: Dictionary в Python. По мотивам Objects/dictnotes.txt

>>> d = {}

piątek, 30 sierpnia 13

Page 64: Dictionary в Python. По мотивам Objects/dictnotes.txt

d = dict.fromkeys(words[:5])# 40% коллизий# Заполнен на ⅔, resize

piątek, 30 sierpnia 13

Page 65: Dictionary в Python. По мотивам Objects/dictnotes.txt

d['abash'] = None# размер ×4 до 32# 0% коллизий

piątek, 30 sierpnia 13

Page 66: Dictionary в Python. По мотивам Objects/dictnotes.txt

d = dict.fromkeys(words[:21])# 29% коллизий# Заполнен на ⅔

piątek, 30 sierpnia 13

Page 67: Dictionary в Python. По мотивам Objects/dictnotes.txt

d['abode'] = None# размер ×4 до 128# 9% коллизий

piątek, 30 sierpnia 13

Page 68: Dictionary в Python. По мотивам Objects/dictnotes.txt

d = dict.fromkeys(words[:85])# 33% коллизий# Заполнен на ⅔

piątek, 30 sierpnia 13

Page 69: Dictionary в Python. По мотивам Objects/dictnotes.txt

Время доступа к элементам

Растет по мере заполнения словаря

Затем резко умешьшается после изменения размера

Среднее время доступа ОК

piątek, 30 sierpnia 13

Page 70: Dictionary в Python. По мотивам Objects/dictnotes.txt

Поиски vs размер

piątek, 30 sierpnia 13

Page 71: Dictionary в Python. По мотивам Objects/dictnotes.txt

Время vs размер

piątek, 30 sierpnia 13

Page 72: Dictionary в Python. По мотивам Objects/dictnotes.txt

Удаление элементов

Не уменьшает размер таблицы

Таблица может уменьшиться только при добавлении элементов

piątek, 30 sierpnia 13

Page 73: Dictionary в Python. По мотивам Objects/dictnotes.txt

Порядок элементов

Во время изменения размера порядок элементов может полностью поменяться

Добавление элементов во время итерации запрещеноRuntimeError: dictionary changed size during iteration

piątek, 30 sierpnia 13

Page 74: Dictionary в Python. По мотивам Objects/dictnotes.txt

Свой __hash__()

Хорошо перемешать биты

Равные хеши для равных элементов

__eq__() должен быть

Быстро вычисляется

piątek, 30 sierpnia 13

Page 75: Dictionary в Python. По мотивам Objects/dictnotes.txt

Пример __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

Page 76: Dictionary в Python. По мотивам Objects/dictnotes.txt

oCERT #2011-003

Хэш для str, bytes и datetime смешивается с "солью" уникальной для каждого процесса Python

pre 3.3: -R option 3.3: by default

piątek, 30 sierpnia 13

Page 77: Dictionary в Python. По мотивам Objects/dictnotes.txt

Python 3: Split-table словари. Общая таблица с ключами для разных таблиц со значениями

piątek, 30 sierpnia 13