While profiling a piece of python code (python 2.6
up to 3.2
), I discovered that the
str
method to convert an object (in my case an integer) to a string is almost an order of magnitude slower than using string formatting.
Here is the benchmark
>>> from timeit import Timer
>>> Timer('str(100000)').timeit()
0.3145311339386332
>>> Timer('"%s"%100000').timeit()
0.03803517023435887
Does anyone know why this is the case? Am I missing something?
python
string
performance
python-3.x
python-2.7
Luca Sbardella
sumber
sumber
'{}'.format(100000)
Jawaban:
'%s' % 100000
dievaluasi oleh kompilator dan setara dengan konstanta pada waktu proses.>>> 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
%
dengan ekspresi run-time tidak (secara signifikan) lebih cepat daristr
:>>> Timer('str(x)', 'x=100').timeit() 0.25641703605651855 >>> Timer('"%s" % x', 'x=100').timeit() 0.2169809341430664
Perhatikan bahwa
str
masih sedikit lebih lambat, seperti yang dikatakan @DietrichEpp, ini karenastr
melibatkan operasi pencarian dan pemanggilan fungsi, sementara%
mengkompilasi ke satu bytecode langsung:>>> 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
Tentu saja hal di atas berlaku untuk sistem yang saya uji (CPython 2.7); implementasi lain mungkin berbeda.
sumber
str
. Thanks for answer. No reason to change code everywhere :-)str
is a name that can be rebound to something other than the string type, but string formatting - i.e. thestr.__mod__
method - cannot be replaced, which permits the compiler to do the optimization. The compiler doesn't do very much in the way of optimization, but it does more than you might think :)Salah satu alasan yang terlintas dalam pikiran adalah fakta yang
str(100000)
melibatkan pencarian global, tetapi"%s"%100000
tidak. Thestr
global yang harus mendongak dalam lingkup global. Ini tidak memperhitungkan seluruh perbedaan:>>> Timer('str(100000)').timeit() 0.2941889762878418 >>> Timer('x(100000)', 'x=str').timeit() 0.24904918670654297
Seperti dicatat oleh thg435 ,
>>> Timer('"%s"%100000',).timeit() 0.034214019775390625 >>> Timer('"%s"%x','x=100000').timeit() 0.2940788269042969
sumber