python - Lista vs velocidad de comprensión del generador con función de unión
python-2.7 list-comprehension (1)
El método
str.join
convierte su parámetro iterable en una lista si aún no es una lista o tupla.
Esto permite que la lógica de unión repita los elementos varias veces (hace una pasada para calcular el tamaño de la cadena de resultados, luego una segunda pasada para copiar los datos).
Puede ver esto en el código fuente de CPython :
PyObject *
PyUnicode_Join(PyObject *separator, PyObject *seq)
{
/* lots of variable declarations at the start of the function omitted */
fseq = PySequence_Fast(seq, "can only join an iterable");
/* ... */
}
La función
PySequence_Fast
en la API de C hace exactamente lo que describí.
Convierte un iterativo arbitrario en una lista (esencialmente llamando a la
list
), a menos que ya sea una lista o una tupla.
La conversión de la expresión del generador a una lista significa que los beneficios habituales de los generadores (una huella de memoria más pequeña y el potencial de cortocircuito) no se aplican a
str.join
, por lo que la sobrecarga adicional (pequeña) que tiene el generador empeora su rendimiento.
Esta pregunta ya tiene una respuesta aquí:
Así que obtuve estos ejemplos de la documentación oficial. https://docs.python.org/2/library/timeit.html
¿Qué hace que el primer ejemplo (expresión del generador) sea más lento que el segundo (comprensión de la lista)?
>>> timeit.timeit(''"-".join(str(n) for n in range(100))'', number=10000)
0.8187260627746582
>>> timeit.timeit(''"-".join([str(n) for n in range(100)])'', number=10000)
0.7288308143615723