‘{0}’. Format () es más rápido que str () y ‘{}’. Format () usando IPython% timeit y, por lo demás, usando Python puro

Así que es una cosa de CPython, no muy seguro de que tenga el mismo comportamiento con otras implementaciones.

Pero '{0}'.format() es más rápido que str() y '{}'.format() . Estoy publicando resultados de Python 3.5.2 , pero lo probé con Python 2.7.12 y la tendencia es la misma.

 %timeit q=['{0}'.format(i) for i in range(100, 100000, 100)] %timeit q=[str(i) for i in range(100, 100000, 100)] %timeit q=['{}'.format(i) for i in range(100, 100000, 100)] 1000 loops, best of 3: 231 µs per loop 1000 loops, best of 3: 298 µs per loop 1000 loops, best of 3: 434 µs per loop 

De los documentos en el object.__str__(self)

Llamado por str(object) y las funciones incorporadas format() e print() para calcular la representación de cadena “informal” o bien imprimible de un objeto.

Entonces, str() y format() llaman al mismo object.__str__(self) método object.__str__(self) , pero ¿de dónde proviene esa diferencia en la velocidad?

ACTUALIZACIÓN como @StefanPochmann y @Leon señalaron en los comentarios, obtienen resultados diferentes. Intenté ejecutarlo con python -m timeit "..." y tienen razón, porque los resultados son:

 $ python3 -m timeit "['{0}'.format(i) for i in range(100, 100000, 100)]" 1000 loops, best of 3: 441 usec per loop $ python3 -m timeit "[str(i) for i in range(100, 100000, 100)]" 1000 loops, best of 3: 297 usec per loop $ python3 -m timeit "['{}'.format(i) for i in range(100, 100000, 100)]" 1000 loops, best of 3: 420 usec per loop 

Entonces parece que IPython está haciendo algo extraño …

NUEVA PREGUNTA : ¿Cuál es la forma preferida de convertir un objeto a str por velocidad?

El tiempo de IPython está desactivado por alguna razón (sin embargo, cuando se probó con una cadena de formato más larga en diferentes celdas, se comportó un poco mejor ). Tal vez ejecutar en las mismas celdas no es correcto, realmente no lo sé.

De cualquier manera, "{}" es un poco más rápido que "{pos}" que es más rápido que "{name}" mientras que todos son más lentos que str .

str(val) es la forma más rápida de transformar un objeto en str ; llama directamente al __str__ los objetos, si existe, y devuelve la cadena resultante. Otros, como format , (o str.format ) incluyen una sobrecarga adicional debido a una llamada de función adicional (para format ); manejar cualquier argumento, analizar la cadena de formato y luego invocar el __str__ de sus args .

Para los métodos str.format "{}" usa numeración automática; de una pequeña sección en los documentos en la syntax de formato :

Modificado en la versión 3.1: Los especificadores de argumentos posicionales pueden omitirse, por lo que '{} {}' es equivalente a '{0} {1}' .

es decir, si proporciona una cadena de la forma:

 "{}{}{}".format(1, 2, 3) 

CPython inmediatamente sabe que esto es equivalente a:

 "{0}{1}{2}".format(1, 2, 3) 

Con una cadena de formato que contiene números que indican posiciones; CPython no puede asumir un número estrictamente creciente (que comienza desde 0 ) y debe analizar cada corchete para poder hacerlo correctamente, reduciendo un poco la velocidad en el proceso:

 "{1}{2}{0}".format(1, 2, 3) 

Por eso tampoco está permitido mezclar estos dos juntos:

 "{1}{}{2}".format(1, 2, 3) 

obtendrá un buen ValueError cuando intente hacerlo:

 ValueError: cannot switch from automatic field numbering to manual field specification 

también toma estos posicionales con PySequence_GetItem que estoy bastante seguro de que es rápido, al menos, en comparación con PyObject_GetItem [ver más PyObject_GetItem ].

Para los valores de "{name}" , CPython siempre tiene trabajo adicional que hacer debido al hecho de que estamos tratando con argumentos de palabras clave en lugar de posicionales; Esto incluye cosas como la construcción del diccionario para las llamadas y la generación de más instrucciones de código de bytes de LOAD para cargar key y valores. La forma de palabra clave de la función de llamada siempre introduce algo de sobrecarga. Además, parece que el acaparamiento realmente utiliza PyObject_GetItem que PyObject_GetItem una sobrecarga adicional debido a su naturaleza genérica.