Podczas profilowania fragmentu kodu Pythona ( python 2.6
aż do 3.2
) odkryłem, że
str
metoda konwersji obiektu (w moim przypadku liczby całkowitej) na ciąg jest prawie o rząd wielkości wolniejsza niż przy użyciu formatowania ciągów.
Oto punkt odniesienia
>>> from timeit import Timer
>>> Timer('str(100000)').timeit()
0.3145311339386332
>>> Timer('"%s"%100000').timeit()
0.03803517023435887
Czy ktoś wie, dlaczego tak się dzieje? Czy coś mi brakuje?
python
string
performance
python-3.x
python-2.7
Luca Sbardella
źródło
źródło
'{}'.format(100000)
Odpowiedzi:
'%s' % 100000
jest oceniany przez kompilator i jest równoważny ze stałą w czasie wykonywania.>>> 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
%
z wyrażeniem czasu wykonywania nie jest (znacząco) szybszy niżstr
:>>> Timer('str(x)', 'x=100').timeit() 0.25641703605651855 >>> Timer('"%s" % x', 'x=100').timeit() 0.2169809341430664
Zwróć uwagę, że
str
jest to wciąż nieco wolniejsze, jak powiedział @DietrichEpp, ponieważstr
obejmuje operacje wyszukiwania i wywołania funkcji, podczas gdy%
kompiluje się do pojedynczego bezpośredniego kodu bajtowego:>>> 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
Oczywiście powyższe odnosi się do systemu, na którym testowałem (CPython 2.7); inne implementacje mogą się różnić.
źródło
str
. Dziękuję za odpowiedź. Nie ma powodu, żeby wszędzie zmieniać kod :-)str
to nazwa, która może być powiązana z czymś innym niż typ łańcucha, ale formatowania łańcucha - tj.str.__mod__
Metody - nie można zastąpić, co pozwala kompilatorowi na wykonanie optymalizacji. Kompilator nie robi zbyt wiele w zakresie optymalizacji, ale robi więcej niż mogłoby się wydawać :)Jednym z powodów, które przychodzą na myśl, jest fakt, że
str(100000)
obejmuje wyszukiwanie globalne, ale"%s"%100000
tak nie jest.str
Globalny musi być spojrzał w zasięgu globalnym. To nie wyjaśnia całej różnicy:>>> Timer('str(100000)').timeit() 0.2941889762878418 >>> Timer('x(100000)', 'x=str').timeit() 0.24904918670654297
Jak zauważył thg435 ,
>>> Timer('"%s"%100000',).timeit() 0.034214019775390625 >>> Timer('"%s"%x','x=100000').timeit() 0.2940788269042969
źródło