O ponto importante é que a compreensão da lista cria uma nova lista. O gerador cria um objeto iterável que "filtra" o material de origem rapidamente enquanto você consome os bits.
Imagine que você tem um arquivo de log de 2 TB chamado "hugefile.txt" e deseja o conteúdo e o comprimento de todas as linhas que começam com a palavra "ENTRY".
Então, tente começar escrevendo uma lista de compreensão:
logfile = open("hugefile.txt","r")
entry_lines = [(line,len(line)) for line in logfile if line.startswith("ENTRY")]
Isso reduz o arquivo inteiro, processa cada linha e armazena as linhas correspondentes em sua matriz. Essa matriz pode, portanto, conter até 2 TB de conteúdo. É muita RAM e provavelmente não é prático para seus propósitos.
Então, em vez disso, podemos usar um gerador para aplicar um "filtro" ao nosso conteúdo. Nenhum dado é realmente lido até começarmos a iterar sobre o resultado.
logfile = open("hugefile.txt","r")
entry_lines = ((line,len(line)) for line in logfile if line.startswith("ENTRY"))
Ainda nem uma única linha foi lida em nosso arquivo. De fato, digamos que queremos filtrar ainda mais nosso resultado:
long_entries = ((line,length) for (line,length) in entry_lines if length > 80)
Ainda nada foi lido, mas especificamos agora dois geradores que atuarão em nossos dados conforme desejamos.
Vamos escrever nossas linhas filtradas para outro arquivo:
outfile = open("filtered.txt","a")
for entry,length in long_entries:
outfile.write(entry)
Agora lemos o arquivo de entrada. Como nosso for
loop continua solicitando linhas adicionais, o long_entries
gerador exige linhas do entry_lines
gerador, retornando apenas aquelas cujo comprimento é superior a 80 caracteres. Por sua vez, o entry_lines
gerador solicita linhas (filtradas conforme indicado) ao logfile
iterador, que por sua vez lê o arquivo.
Portanto, em vez de "enviar" dados para sua função de saída na forma de uma lista totalmente preenchida, você está dando à função de saída uma maneira de "extrair" dados apenas quando necessário. No nosso caso, isso é muito mais eficiente, mas não tão flexível. Geradores são uma maneira, uma passagem; os dados do arquivo de log que lemos são imediatamente descartados; portanto, não podemos voltar à linha anterior. Por outro lado, não precisamos nos preocupar em manter os dados por perto quando terminarmos.
[exp for x in iter]
ser apenas açúcarlist((exp for x in iter))
? ou existe uma diferença de execução?