El punto importante es que la comprensión de la lista crea una nueva lista. El generador crea un objeto iterable que "filtrará" el material de origen sobre la marcha a medida que consume los bits.
Imagine que tiene un archivo de registro de 2TB llamado "hugefile.txt", y desea el contenido y la longitud de todas las líneas que comienzan con la palabra "ENTRY".
Así que intenta comenzar escribiendo una lista de comprensión:
logfile = open("hugefile.txt","r")
entry_lines = [(line,len(line)) for line in logfile if line.startswith("ENTRY")]
Esto absorbe todo el archivo, procesa cada línea y almacena las líneas coincidentes en su matriz. Por lo tanto, esta matriz podría contener hasta 2 TB de contenido. Eso es mucha RAM, y probablemente no sea práctico para sus propósitos.
Por lo tanto, podemos usar un generador para aplicar un "filtro" a nuestro contenido. En realidad, no se leen datos hasta que comenzamos a iterar sobre el resultado.
logfile = open("hugefile.txt","r")
entry_lines = ((line,len(line)) for line in logfile if line.startswith("ENTRY"))
Ni siquiera se ha leído una sola línea de nuestro archivo todavía. De hecho, digamos que queremos filtrar nuestro resultado aún más:
long_entries = ((line,length) for (line,length) in entry_lines if length > 80)
Todavía no se ha leído nada, pero ahora hemos especificado dos generadores que actuarán sobre nuestros datos como lo deseamos.
Vamos a escribir nuestras líneas filtradas a otro archivo:
outfile = open("filtered.txt","a")
for entry,length in long_entries:
outfile.write(entry)
Ahora leemos el archivo de entrada. A medida que nuestro for
bucle continúa solicitando líneas adicionales, el long_entries
generador exige líneas del entry_lines
generador, devolviendo solo aquellas cuya longitud es mayor a 80 caracteres. Y a su vez, el entry_lines
generador solicita líneas (filtradas como se indica) del logfile
iterador, que a su vez lee el archivo.
Entonces, en lugar de "enviar" datos a su función de salida en forma de una lista completamente poblada, le está dando a la función de salida una forma de "extraer" datos solo cuando sea necesario. Esto es en nuestro caso mucho más eficiente, pero no tan flexible. Los generadores son unidireccionales, un paso; los datos del archivo de registro que hemos leído se descartan de inmediato, por lo que no podemos volver a una línea anterior. Por otro lado, no tenemos que preocuparnos por mantener los datos una vez que hayamos terminado con ellos.
[exp for x in iter]
ser solo azúcarlist((exp for x in iter))
? o hay una diferencia de ejecución?