Eleneldil G. Arilou (arilou) wrote,
Eleneldil G. Arilou
arilou

Форматирование строк в питое. Удивление.

Задумавшись вдруг, а какой тип подстановки данных в строку использовать, старый (через %) или новый (через str.format) попробовал сравнение для простых случаев.


>>> from timeit import timeit as ti
>>> ti("'%s as `%s`' % ('1','b')") / ti("'{0} as `{1}`'.format('1','b')")
0.52343018570438449
>>> ti("'%d as `%s`' % (1,'b')") / ti("'{0} as `{1}`'.format('1','b')")
1.7450242496291981
>>> ti("'%d as `%s`' % (1,'b')") / ti("'{0} as `{1}`'.format(1,'b')")
1.4912612933641076
>>> ti("'%r as `%s`' % (1,'b')") / ti("'{0} as `{1}`'.format(1,'b')")
0.5603779016127246
>>> ti("'%d as `%s`' % (1,'b')") / ti("'{0} as `{1}`'.format(1,'b')")
1.512150710318646
>>> ti("'%s as `%s`' % (1,'b')") / ti("'{0} as `{1}`'.format(1,'b')")
0.54302277029435786
>>> ti("'{0:d} as `{1}`'.format(1,'b')") / ti("'{0} as `{1}`'.format(1,'b')")
1.0985406776607249
>>> ti("'%d as `%s`' % (1,'b')") / ti("'%s as `%s`' % (1,'b')")
2.745502767603925
>>> ti("'%s as `%s`' % v", "v=('1','b')") / ti("'{0[0]} as `{0[1]}`'.format(v)", "v=('1','b')")
0.29668838868224023

Что получается:

1) Для подставновки строк старое форматирование быстрее нового почти в 2 раза.
1а) А если строки уже собраны в кортеж или список, то более чем в 3 раза.

2) Для обоих способов для чисел явное указание числового формата (без уточнений, просто букву 'd' или 'f') работает дольше, чем указание строкового, вызывающее автоматическое приведение числового аргумента к строке.
2a) Но для старого форматирования разница огромна, а для нового -- неочень.

Была надежда, что как-то новый формат оправдается, когда за значениями для подстановки надо залазить куда-то глубоко, причём часть пути совпадает:

>>> aa = A()
>>> aa.val = {1: ('a', 'b', 'c')}
>>> ti("'`%s`, `%s`, `%s`' % (aa.val[1][1], aa.val[1][0], aa.val[1][2])", "from __main__ import aa") / ti("'`{0[1]}`, `{0[0]}`, `{0[2]}`'.format(aa.val[1])", "from __main__ import aa")
0.6678787220617175

Не вышло. Видимо, в случае старого форматирования питон соптимизировал три подряд обращения к aa.val[1].

>>> def aaf(n):
return aa.val[n]
>>> ti("'`%s`, `%s`, `%s`' % (aaf(1)[1], aaf(1)[0], aaf(1)[2])", "from __main__ import aaf") / ti("'`{0[1]}`, `{0[0]}`, `{0[2]}`'.format(aaf(1))", "from __main__ import aaf")
0.85738243476836973

То ли питон и тут определил, что результат вызова aaf(1) можно закешировать и не звать его трижды, то ли экономия двух вызовов aaf() (внутри которой -- обращение за атрибутом класса, а потом за значением из словаря) не способна полностью окупть потери скорости нового форматирования. В итоге, одно из удобств нового форматирования -- то, что любой из параметров можно использовать неоднократно -- так же не даёт большого выигрыша (хотя проигрыш уже заметно меньше, чем в 2 раза).

Да, я понимаю, что наверняка найдутся случаи, когда старый синтаксис форматирования просто не даст нужного результата. Или, быть может, породит решающим образом более нечитабельный код, чем новое форматирование. Но в целом вывод получается такой, что лучше использовать %-форматирование, пока нет явной потрбности в str.format.

И с выводом чисел, если нет ни одного из условий:
1) требуется явно задать формат вывода числа (десятичные знаки и прочее),
2) требуется получить Exception, если в параметре вдруг оказалось не число,
3) хочется, чтобы причтении кода строка формата поясняла/напоминала, что ожидается от аргументов
-- то лучше ставить %s (ну или не упоминать числовой формат в случае нового форматирования), и питон автоматически приобразует число к строке быстрее, чем по явному указанию.

Ну а теперь, кто тут опытне меня в питоне, скажите, пожалуйста, что я упустил?


P.S.: Критерий "кому как больше по вкусу" сознательно не рассматривался.

This entry was originally posted at http://arilou.dreamwidth.org/904415.html. Please comment there using OpenID.
Tags: python, программирование
Subscribe
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments