str prestazioni in python


88

Mentre profilavo un pezzo di codice Python ( python 2.6fino a 3.2), ho scoperto che il strmetodo per convertire un oggetto (nel mio caso un intero) in una stringa è quasi un ordine di grandezza più lento rispetto all'utilizzo della formattazione della stringa.

Ecco il punto di riferimento

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

Qualcuno sa perché questo è il caso? Mi sto perdendo qualcosa?


2
E che dire di'{}'.format(100000)
wim

Questo è il più lento ma anche il più flessibile.
Luca Sbardella

Risposte:


106

'%s' % 100000 viene valutato dal compilatore ed è equivalente a una costante in fase di esecuzione.

>>> 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        

%con un'espressione di runtime non è (significativamente) più veloce di str:

>>> Timer('str(x)', 'x=100').timeit()
0.25641703605651855
>>> Timer('"%s" % x', 'x=100').timeit()
0.2169809341430664

Nota che strè ancora leggermente più lento, come ha detto @DietrichEpp, questo perché strimplica operazioni di ricerca e chiamata di funzione, mentre %compila in un singolo bytecode immediato:

>>> 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        

Ovviamente quanto sopra è vero per il sistema su cui ho testato (CPython 2.7); altre implementazioni possono differire.


In effetti questo sembra il motivo, ho appena provato me stesso e la formattazione delle stringhe è solo circa il 5% più veloce di str. Grazie per la risposta. Nessun motivo per cambiare codice ovunque :-)
Luca Sbardella

2
Per elaborare ulteriormente: strè un nome che può essere ricollegato a qualcosa di diverso dal tipo di stringa, ma la formattazione della stringa - cioè il str.__mod__metodo - non può essere sostituita, il che consente al compilatore di eseguire l'ottimizzazione. Il compilatore non fa molto in termini di ottimizzazione, ma fa più di quanto potresti pensare :)
Karl Knechtel

4
... e la lezione da imparare qui è: non usare mai i letterali in test come questi!
UncleZeiv

Questo particolare post di blog potrebbe interessarti: skymind.com/~ocrow/python_string . Contiene un grafico di benchmark per vari metodi di concatenazione di stringhe simili a quelli forniti sopra.
Aaron Newton

14

Uno dei motivi che viene in mente è il fatto che str(100000)implica una ricerca globale, ma "%s"%100000non lo fa. Il strglobale deve essere esaminato nell'ambito globale. Questo non tiene conto dell'intera differenza:

>>> Timer('str(100000)').timeit()
0.2941889762878418
>>> Timer('x(100000)', 'x=str').timeit()
0.24904918670654297

Come notato da thg435 ,

>>> Timer('"%s"%100000',).timeit()
0.034214019775390625
>>> Timer('"%s"%x','x=100000').timeit()
0.2940788269042969
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.