При профилировании фрагмента кода Python ( python 2.6
до 3.2
) я обнаружил, что
str
метод преобразования объекта (в моем случае целого числа) в строку почти на порядок медленнее, чем при использовании форматирования строки.
Вот эталон
>>> from timeit import Timer
>>> Timer('str(100000)').timeit()
0.3145311339386332
>>> Timer('"%s"%100000').timeit()
0.03803517023435887
Кто-нибудь знает, почему это так? Я что-то упускаю?
python
string
performance
python-3.x
python-2.7
Лука Сбарделла
источник
источник
'{}'.format(100000)
Ответы:
'%s' % 100000
оценивается компилятором и эквивалентна константе во время выполнения.>>> import dis >>> dis.dis(lambda: str(100000)) 8 0 LOAD_GLOBAL 0 (str) 3 LOAD_CONST 1 (100000) 6 CALL_FUNCTION 1 9 RETURN_VALUE >>> dis.dis(lambda: '%s' % 100000) 9 0 LOAD_CONST 3 ('100000') 3 RETURN_VALUE
%
с выражением времени выполнения не (значительно) быстрее, чемstr
:>>> Timer('str(x)', 'x=100').timeit() 0.25641703605651855 >>> Timer('"%s" % x', 'x=100').timeit() 0.2169809341430664
Обратите внимание, что
str
это все еще немного медленнее, как сказал @DietrichEpp, потому чтоstr
включает операции поиска и вызова функций, а%
компилируется в один непосредственный байт-код:>>> dis.dis(lambda x: str(x)) 9 0 LOAD_GLOBAL 0 (str) 3 LOAD_FAST 0 (x) 6 CALL_FUNCTION 1 9 RETURN_VALUE >>> dis.dis(lambda x: '%s' % x) 10 0 LOAD_CONST 1 ('%s') 3 LOAD_FAST 0 (x) 6 BINARY_MODULO 7 RETURN_VALUE
Конечно, вышесказанное верно для системы, на которой я тестировал (CPython 2.7); другие реализации могут отличаться.
источник
str
. Спасибо за ответ. Нет причин менять код везде :-)str
это имя, которое может быть повторно связано с чем-то другим, кроме строкового типа, но форматирование строки - то естьstr.__mod__
метод - не может быть заменено, что позволяет компилятору выполнить оптимизацию. Компилятор не слишком много оптимизирует, но он делает больше, чем вы думаете :)Одна из причин, которые приходят на ум, - это тот факт, что
str(100000)
глобальный поиск требует, но"%s"%100000
не делает этого.str
Глобальное должно быть ищутся в глобальном масштабе. Это не объясняет всей разницы:>>> Timer('str(100000)').timeit() 0.2941889762878418 >>> Timer('x(100000)', 'x=str').timeit() 0.24904918670654297
Как отмечает thg435 ,
>>> Timer('"%s"%100000',).timeit() 0.034214019775390625 >>> Timer('"%s"%x','x=100000').timeit() 0.2940788269042969
источник