str продуктивність в python


88

Профілюючи шматок коду python ( python 2.6до 3.2), я виявив, що strметод перетворення об'єкта (у моєму випадку цілого числа) у рядок майже на порядок повільніший, ніж використання форматування рядків.

Ось еталон

>>> from timeit import Timer
>>> Timer('str(100000)').timeit()
0.3145311339386332
>>> Timer('"%s"%100000').timeit()
0.03803517023435887

Хтось знає, чому це так? Мені чогось не вистачає?


2
А як щодо'{}'.format(100000)
wim

Це найповільніше, але також і найбільш гнучке.
Luca Sbardella

Відповіді:


106

'%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); інші реалізації можуть відрізнятися.


Насправді це виглядає як причина, я щойно спробував і форматування рядків приблизно на 5% швидше, ніж str. Дякую за відповідь. Немає причин міняти код скрізь :-)
Лука Сбарделла

2
Подальше уточнення: strце ім'я, яке можна відскочити до чогось іншого, ніж тип рядка, але форматування рядка - тобто str.__mod__метод - не може бути замінено, що дозволяє компілятору зробити оптимізацію. Компілятор робить не так багато для оптимізації, але робить більше, ніж ви можете подумати :)
Карл Кнехтель

4
... і урок, який слід засвоїти тут, такий: ніколи не використовуйте літерали в таких тестах!
UncleZeiv

Цей конкретний запис у блозі може вас зацікавити: skymind.com/~ocrow/python_string . Він містить діаграму еталонів для різних методів конкатенації рядків, подібних до того, що ви надали вище.
Аарон Ньютон,

14

Однією з причин, яка спадає на думку, є той факт, що 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.