11 марта 2015 г.

Fast Python. Выпуск 1. Обновление словарей

Привет! Запускаю раздел Fast Python, в котором буду делиться простыми рецептами про то, как ускорить и оптимизировать выполнение кода на Python.

Первый выпуск будет посвящен обновлению данных в словарях. Словари - одни из найболее часто используемых типов данных в Python. И сколько времени я с ними не работаю, у меня никогда не возникал вопрос как правильней обновить данные в словаре. Я для себя всегда отвечал на него, что правильней обновлять используя метод update, но сегодня с утра наткнулся на твит от Брэда Монтгомери и мой мир изменился.

Оказывается, что более правильным с точки зрения скорости является обновление словаря через поочередное присваивание значений, чем единичный апдейт. Не верите? Результаты замеров весьма красноречивы:

Python 3.4.3

In [2]: timeit("d = {}; d.update({'first': 'first', 'second': ['one', 'two', 'three'], 'third': True})", number=1000000)
Out[2]: 0.9664371280086925

In [3]: timeit("d = {}; d['first'] = 'first'; d['second'] = ['one', 'two', 'three']; d['third'] = True", number=1000000)                                      
Out[3]: 0.4200690069992561

Python 2.7.9

In [2]: timeit("d = {}; d.update({'first': 'first', 'second': ['one', 'two', 'three'], 'third': True})", number=1000000)
Out[2]: 1.0035829544067383

In [3]: timeit("d = {}; d['first'] = 'first'; d['second'] = ['one', 'two', 'three']; d['third'] = True", number=1000000)
Out[3]: 0.5186400413513184

Bonus: PyPy 2.4.0

>>>> timeit("d = {}; d.update({'first': 'first', 'second': ['one', 'two', 'three'], 'third': True})", number=1000000)                                               
0.10811400413513184
>>>> timeit("d = {}; d['first'] = 'first'; d['second'] = ['one', 'two', 'three']; d['third'] = True", number=1000000)                                         
0.005925893783569336

Итого: Если вы где-то в коде увидите обновление одиночного или множественных элементов словаря через .update - смело переписывайте этот фрагмент на использование __setitem__.

Fast Python:

data['key'] = 'value'
data['another-key'] = 'another-value'

Slow Python:

data.update({
    'key': 'value',
    'another-key': 'another-value',
})

UPD: Михаил Кривушин (deepwalker) в комментариях объяснил почему так происходит:

По дороге создается еще один словарь, и потом уже из него копируются элементы
https://gist.github.com/Deepwalker/c52a74c26df0707dd303

UPD2: Если ключи словаря не используют специальных символов и являются валидными Python ключами, то лучше использовать синтаксис .update(key='value'), вместо .update({'key': 'value'}):

Python 3.4.3

In [2]: timeit("d = {}; d.update(first='first', second=['one', 'two', 'three'], third=True)", number=1000000)
Out[2]: 0.88018084000214

Python 2.7.9

In [2]: timeit("d = {}; d.update(first='first', second=['one', 'two', 'three'], third=True)", number=1000000)
Out[2]: 0.7820448875427246

PyPy 2.4.0

>>>> timeit("d = {}; d.update(first='first', second=['one', 'two', 'three'], third=True)", number=1000000)
0.010169029235839844

blog comments powered by Disqus