?

Log in

No account? Create an account

Питон, строки, продолжаю измерять. - Узором созвездий по мантии ночи

27.03.2013, Среда

23:44:00 - Питон, строки, продолжаю измерять.

Previous Entry Поделиться Next Entry

В продолжение предыдущего поста
Взявшись убрать из кода пару-тройку свеже вписанных str.format, задумался и о скорости сцепки коротких строк.

Первые приходящие в голову способы:
1) %-форматирование
2) "Сложение" строк (str1 + str2)
3) ''.join(seq)
Третий способ бесспорно удобен, когда seq (кортеж, список, итератор) в нужном порядке у нас уже готов. А если есть отдельные строки, то он выглядит уже менее красиво: ''.join((str1, str2)). Однако, в книжках было написано, что ''.join имеет то преимущество перед "сложением", что при сцепке более двух строк не создаёт промежуточные результаты.

Беру в руки секуномер...

from timeit import timeit as ti, repeat as tir
>>> def ti_cmp(stmt1, stmt2, rep=6):
... return map(lambda x, y: '%.4f' % (x / y), tir(stmt1, repeat=rep) , tir(stmt2, repeat=rep))
...

Замеряю...

>>> ti("'`%s`' % 'qwerty'") / ti ("''.join(('`', 'qwerty', '`'))")
0.15900281982625888

Получается, на мелких сцепках ''.join вреден.

>>> ti_cmp("'`%s`' % 'qwerty'", "'`' + 'qwerty' + '`'")
['1.0109', '1.0030', '0.9626', '0.9643', '1.0066', '0.9976']

Тут практически одинаково. Но чуть усложним, и...

>>> ti_cmp("'`%s` as `%s`' % ('qwerty', 'qqq')", "'`' + 'qwerty' + '` as `' + 'qqq' + '`'")
['6.9943', '6.9009', '6.9742', '6.9735', '6.8879', '6.9646']
>>> ti_cmp("'`%s` as `%s`' % ('qwerty', 'qqq')", "''.join(('`','qwerty','` as `','qqq','`'))")
['0.8639', '0.8592', '0.9210', '0.8885', '0.8638', '0.8628']

Форматирование безнадёжно проигрывает "сложению", хотя ещё выигрывает у ''.join.
Заодно проверил, что будет, если кортеж для ''.join заготовить заранее:

>>> tpl = ('`','qwerty','` as `','qqq','`')
>>> ti("''.join(tpl)", "from __main__ import tpl") / ti ("''.join(('`', 'qwerty', '` as `', 'qqq', '`'))")
1.0001781231845137
>>> ti("''.join(tpl)", "from __main__ import tpl") / ti ("''.join(('`', 'qwerty', '` as `', 'qqq', '`'))")
0.99115275922939039

Т.е. практически без разницы, поиск переменной tpl занимает время, сравнимое с временем создания небольшого кортежа на лету.

И того, на маленьких строках "сложение" уверенно лидирует, хотя в совсем коротком случае %-форматирование даёт тот же результат.

Где же ужасы создания промежуточных строк при "сложении"?

>>> ti ("'`' + 'qwerty' + '` as `' + 'qqq' + '`'") / ti ("''.join(('`', 'qwerty', '` as `', 'qqq', '`'))")
0.1214502923338789
>>> ti ("'`' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '`'") / ti ("''.join(('`', 'qwertyqwertyqwerty', '` as `', 'qqq', '`'))")
0.71356679587553884
>>> ti ("'SELECT `' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '`'") / ti ("''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '`'))")
0.97721257775680759
>>> ti ("'SELECT `' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '` FROM DB'") / ti ("''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB'))")
1.0434518569843669
>>> ti("'SELECT `' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '` FROM DB WHERE `' + 'a' + '` = 0'") / ti("''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = 0'))")
1.3793693084449092
>>> ti("'SELECT `' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '` FROM DB WHERE `' + 'a' + '` = 0' + ' '") / ti("''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = 0', ' '))")
1.5511805115507227

Ну, вот и они.
А как насчёт %-форматирования на таких строках?

>>> ti_cmp("'SELECT `%s` as `%s` FROM DB WHERE `%s` = 0' % ('qwertyqwertyqwerty','qqq','a')", "''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = 0'))")
['1.0474', '1.0977', '1.0814', '1.0722', '1.0698', '1.0829']
>>> ti_cmp("'SELECT `%s` as `%s` FROM DB WHERE `%s` = %d' % ('qwertyqwertyqwerty','qqq','a',0)", "''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = ', str(0)))")
['1.4546', '1.4273', '1.4362', '1.4385', '1.4560', '1.4595']
>>> ti_cmp("'SELECT `%s` as `%s` FROM DB WHERE `%s` = %d' % ('qwertyqwertyqwerty','qqq','a',0)", "''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = ', format(0, 'd')))")
['1.0202', '1.0167', '1.0175', '1.0276', '1.0193', '1.0053']

Уступает join'у свосем немного. При этом читабельность, я думаю, всё же лучше. (Использование явного форматирования числа как числа, конечно, снижает скорость, но это уже порой необходимость.)


This entry was originally posted at http://arilou.dreamwidth.org/904516.html. Please comment there using OpenID.