Python List Comprehension

Nas aulas anteriores, você escreveu muitas vezes a mesma receita: começar com uma lista vazia, percorrer outra lista com for e ir fazendo append. "As notas de quem passou", "os itens em maiúsculas", "os preços com frete". A receita é tão comum que o Python tem um jeito de escrevê-la em uma linha só: a list comprehension (algo como "compreensão de lista"; em português, muita gente diz só "comprehension" mesmo). Ela é uma das coisas que mais deixam o código com cara de Python, e também uma das mais fáceis de exagerar.

Você vai aprender
  • A ler e escrever [expressão for item in lista], comparando com o for + append.
  • A transformar cada item (maiúsculas, contas, tamanhos) e a usar range().
  • A filtrar com if no fim: só os itens que passam no teste.
  • A escolher entre dois valores com if/else no começo, e por que os dois if ficam em lugares diferentes.
  • Quando não usar: para fazer coisas (como print), quando fica comprida demais, quando precisa de break.
  • Os erros reais: o else no fim, o if sem else no começo, a lista de None, a variável que não existe fora e os parênteses no lugar dos colchetes.

A ideia: descrever a lista em vez de montá-la

Pense em duas maneiras de pedir uma coisa a alguém:

  • Passo a passo: "pegue uma folha em branco; para cada item da minha lista, escreva o item em letras maiúsculas na folha".
  • Descrevendo o resultado: "quero os itens da minha lista, em maiúsculas".

As duas dão a mesma folha. O for com append é o passo a passo; a list comprehension é a descrição. Ela se lê quase como a frase: [item.upper() for item in compras], "o item em maiúsculas, para cada item em compras".


1. Do for para a comprehension

Primeiro, o jeito que você já conhece:

compras = ["arroz", "feijão", "café"]
maiusculas = []
for item in compras:
    maiusculas.append(item.upper())
print(maiusculas)
$ python3 lc_for.py
['ARROZ', 'FEIJÃO', 'CAFÉ']

Agora a mesma coisa, em list comprehension:

compras = ["arroz", "feijão", "café"]
maiusculas = [item.upper() for item in compras]
print(maiusculas)
print(compras)
$ python3 lc.py
['ARROZ', 'FEIJÃO', 'CAFÉ']
['arroz', 'feijão', 'café']
[ … ]
Os colchetes de fora dizem: "o resultado é uma lista". Eles fazem o papel do maiusculas = [].
item.upper()
A expressão: o que vai entrar na lista nova para cada item. Faz o papel do que estava dentro do append(…). Vem primeiro, embora seja calculada a cada volta.
for item in compras
O mesmo for de sempre, só que sem os dois-pontos e sem bloco: diz de onde vêm os itens e o nome de cada um.

Repare na última linha da saída: a lista compras não mudou. A comprehension sempre cria uma lista nova; a original fica como estava.

for + appendList comprehension
maiusculas = []maiusculas = [item.upper() for item in compras]
for item in compras:
maiusculas.append(item.upper())

2. Transformando cada item

A expressão do começo pode ser qualquer coisa que dê um valor: uma conta, uma função, um método. E o for pode percorrer qualquer coisa que um for comum percorreria, como um range() (aula range()):

quadrados = [n * n for n in range(1, 6)]
print(quadrados)
precos = [4.50, 12.00, 8.75]
com_frete = [preco + 0.50 for preco in precos]
print(com_frete)
tamanhos = [len(item) for item in ["arroz", "feijão", "café"]]
print(tamanhos)
$ python3 lc_range.py
[1, 4, 9, 16, 25]
[5.0, 12.5, 9.25]
[5, 6, 4]
  • [n * n for n in range(1, 6)]: para cada n de 1 a 5, o quadrado de n.
  • [preco + 0.50 for preco in precos]: cada preço com R$ 0,50 a mais. Compare com o for com range(len(…)) da aula Alterando Itens: lá a própria lista mudava; aqui nasce uma lista nova e a original fica intacta.
  • [len(item) for item in …]: o tamanho de cada item.

Missão: o programa monta os preços com frete usando for e append. Troque as três linhas do meio por uma list comprehension que dê o mesmo resultado.

precos = [4.50, 12.00, 8.75]
com_frete = []
for preco in precos:
    com_frete.append(preco + 0.50)
print(com_frete)
precos = [4.50, 12.00, 8.75]
com_frete = [preco + 0.50 for preco in precos]
print(com_frete)

3. Filtrando: if no fim

A professora quer só as notas de quem passou. Um if (aula if) no fim da comprehension funciona como uma peneira: o item só entra na lista nova se o teste der verdadeiro.

notas = [7.0, 4.5, 8.5, 6.0, 9.5, 5.0]
aprovadas = [nota for nota in notas if nota >= 6]
print(aprovadas)
turma = ["Ana", "Bruno", "Alice", "Carla", "Artur"]
com_a = [nome for nome in turma if nome.startswith("A")]
print(com_a)
$ python3 lc_if.py
[7.0, 8.5, 6.0, 9.5]
['Ana', 'Alice', 'Artur']
nota
A expressão: o próprio item, sem transformar. (Dá para transformar e filtrar ao mesmo tempo: [nota + 1 for nota in notas if nota >= 6].)
for nota in notas
De onde vêm os itens.
if nota >= 6
A peneira. A nota 4.5 não passa, e simplesmente não entra na lista nova. Por isso a lista nova pode ser menor que a original.

Este é o "jeito de montar uma lista nova só com o que fica", que a aula Removendo Itens recomendou no lugar de remover itens dentro de um for. Ali levou quatro linhas; aqui, uma.

Missão: a lista aprovadas está recebendo todas as notas. Acrescente um if no fim da comprehension para ficarem só as notas 6 ou mais.

notas = [7.0, 4.5, 8.5, 6.0, 9.5, 5.0]
aprovadas = [nota for nota in notas]
print(aprovadas)
notas = [7.0, 4.5, 8.5, 6.0, 9.5, 5.0]
aprovadas = [nota for nota in notas if nota >= 6]
print(aprovadas)

4. Escolhendo entre dois valores: if/else no começo

E se a professora quiser, para cada aluno, a palavra "aprovado" ou "recuperação"? Agora ninguém fica de fora; o que muda é o valor que entra. Isso é o if em uma linha (aula if em uma Linha), e ele vai no começo, no lugar da expressão:

notas = [7.0, 4.5, 8.5, 6.0, 9.5, 5.0]
situacao = ["aprovado" if nota >= 6 else "recuperação" for nota in notas]
print(situacao)
$ python3 lc_ifelse.py
['aprovado', 'recuperação', 'aprovado', 'aprovado', 'aprovado', 'recuperação']
"aprovado" if nota >= 6 else "recuperação"
A expressão inteira: ""aprovado" se a nota for 6 ou mais, senão "recuperação"". Ela sempre dá um valor, e esse valor entra na lista.
for nota in notas
De onde vêm as notas. Seis notas, seis palavras: a lista nova tem o mesmo tamanho da original.

Os dois if, lado a lado

É aqui que quase todo mundo se confunde. Os dois if parecem iguais, mas fazem coisas diferentes e moram em lugares diferentes:

if no fim (filtro)if/else no começo (escolha)
Escrita[nota for nota in notas if nota >= 6]["ok" if nota >= 6 else "rec" for nota in notas]
Pergunta que responde"Este item entra na lista?""Qual valor entra no lugar deste item?"
Tem else?Não: quem não passa fica de foraSim, obrigatório: todo item precisa de um valor
Tamanho da lista novaIgual ou menorSempre igual

Dá para usar os dois juntos: ["ok" if nota >= 9 else "bom" for nota in notas if nota >= 6] primeiro peneira (só as notas 6 ou mais) e depois escolhe a palavra. Funciona, mas repare como já ficou difícil de ler. Guarde essa sensação para a seção 6.


5. Um uso do dia a dia: limpar o que foi digitado

A Ana digitou a lista de compras numa linha só, separada por vírgulas, com espaços sobrando, maiúsculas misturadas e até um item vazio. O split(",") (aula Métodos de Texto) corta o texto nas vírgulas, e a comprehension limpa cada pedaço:

digitado = "  Arroz, feijão ,CAFÉ,  , leite "
itens = [pedaco.strip().lower() for pedaco in digitado.split(",") if pedaco.strip()]
print(itens)
$ python3 lc_limpar.py
['arroz', 'feijão', 'café', 'leite']
  • digitado.split(","): os pedaços entre as vírgulas, com os espaços e tudo.
  • if pedaco.strip(): a peneira. Um pedaço só de espaços, depois do strip(), vira "", e um texto vazio conta como falso (aula Booleanos). Então ele fica de fora.
  • pedaco.strip().lower(): o que entra, sem espaços nas pontas e em minúsculas.

Essa linha já está no limite do confortável. O mesmo programa, com for:

digitado = "  Arroz, feijão ,CAFÉ,  , leite "
itens = []
for pedaco in digitado.split(","):
    pedaco = pedaco.strip()
    if pedaco:
        itens.append(pedaco.lower())
print(itens)
$ python3 lc_limpar2.py
['arroz', 'feijão', 'café', 'leite']

Mais comprido, mas cada linha faz uma coisa só, e o strip() é feito uma vez em vez de duas. Os dois estão certos; escolha o que você (e quem for ler depois) entende mais rápido.


6. Quando não usar

A list comprehension serve para uma coisa: criar uma lista a partir de outra. Fora disso, o for comum é melhor.

Para fazer algo, e não para criar uma lista

compras = ["arroz", "feijão", "café"]
resultado = [print(item) for item in compras]
print(resultado)
$ python3 lc_print.py
arroz
feijão
café
[None, None, None]

Os itens foram mostrados, mas, de quebra, o Python montou uma lista com o que cada print devolveu: None, três vezes (aula O Valor None). Uma lista inútil, criada só para ser jogada fora. Quando o objetivo é fazer algo com cada item (mostrar, gravar num arquivo, fazer append em outra lista), use o for:

compras = ["arroz", "feijão", "café"]
for item in compras:
    print(item)
$ python3 mostrar.py
arroz
feijão
café

A mesma saída, sem lista nenhuma sobrando.

Quando fica comprida ou cheia de condições

Uma comprehension pode ter vários for e vários if. Que lista esta linha monta?

compras = ["arroz", "feijão", "sal", "café"]
consoantes = [letra.upper() for item in compras if len(item) > 3 for letra in item if letra not in "aeiouãé"]
print(consoantes)
$ python3 lc_complicada.py
['R', 'R', 'Z', 'F', 'J', 'C', 'F']

Difícil dizer de cabeça. O mesmo com for:

compras = ["arroz", "feijão", "sal", "café"]
consoantes = []
for item in compras:
    if len(item) > 3:
        for letra in item:
            if letra not in "aeiouãé":
                consoantes.append(letra.upper())
print(consoantes)
$ python3 lc_complicada2.py
['R', 'R', 'Z', 'F', 'J', 'C', 'F']

Agora dá para ler: "para cada item com mais de 3 letras, para cada letra que não é vogal, guarde a letra em maiúscula". (O sal ficou de fora por ter só 3 letras.) Mesmo resultado, muito mais fácil de entender e de consertar.

SituaçãoUse
Uma lista nova, transformando cada itemComprehension: [x * 2 for x in lista]
Uma lista nova, só com alguns itensComprehension com if no fim
Uma lista nova, com um de dois valores para cada itemComprehension com if/else no começo
Fazer algo com cada item (print, gravar, contar)for
Alterar a própria listafor i in range(len(lista)) (aula Alterando Itens)
Parar no meio (break)for: a comprehension não tem break
Não cabe numa linha, ou precisa de mais de um if ou de um for dentro de outrofor: quem lê agradece
Só somar, achar o maior, contarsum(), max(), len() (às vezes com uma comprehension dentro: sum([p * 2 for p in precos]))

Quando dá errado

O else no fim

A professora queria "aprovado" ou "recuperação" e pôs o if/else no fim, onde mora o filtro:

notas = [7.0, 4.5, 8.5]
situacao = ["aprovado" for nota in notas if nota >= 6 else "recuperação"]
print(situacao)
$ python3 lc_erro_else.py
  File "/home/ana/lc_erro_else.py", line 2
    situacao = ["aprovado" for nota in notas if nota >= 6 else "recuperação"]
                                                          ^^^^
SyntaxError: invalid syntax

Linha por linha:

  • File "/home/ana/lc_erro_else.py", line 2: o problema está na linha 2. Sem Traceback: é um erro de escrita, e nada rodou.
  • Os ^^^^ apontam para o else: foi ali que o Python se perdeu.
  • SyntaxError: invalid syntax: "sintaxe inválida". O if do fim é um filtro, e filtro não tem else; o Python não esperava aquela palavra ali.

Como consertar: com else, o if vai para o começo: ["aprovado" if nota >= 6 else "recuperação" for nota in notas].

O if sem else no começo
notas = [7.0, 4.5, 8.5]
aprovadas = [nota if nota >= 6 for nota in notas]
print(aprovadas)
$ python3 lc_erro_ifsem.py
  File "/home/ana/lc_erro_ifsem.py", line 2
    aprovadas = [nota if nota >= 6 for nota in notas]
                 ^^^^^^^^^^^^^^^^^
SyntaxError: expected 'else' after 'if' expression

Agora o erro é o contrário, e o Python 3.14 explica bem: "esperava else depois da expressão if". No começo, o if está escolhendo um valor, e precisa saber o que pôr quando o teste der falso. Os ^^^^ marcam a expressão inteira, nota if nota >= 6. Como consertar: se a ideia era filtrar, mova o if para o fim: [nota for nota in notas if nota >= 6]. Se era escolher, acrescente o else: [nota if nota >= 6 else 0 for nota in notas].

A variável da comprehension não existe fora dela
compras = ["arroz", "feijão", "café"]
maiusculas = [item.upper() for item in compras]
print(maiusculas)
print(item)
$ python3 lc_vazamento.py
['ARROZ', 'FEIJÃO', 'CAFÉ']
Traceback (most recent call last):
  File "/home/ana/lc_vazamento.py", line 4, in <module>
    print(item)
          ^^^^
NameError: name 'item' is not defined. Did you mean: 'iter'?

Depois de um for comum, a variável do laço continua existindo, com o último valor. A da comprehension, não: o item só existe dentro dos colchetes. Fora deles, name 'item' is not defined. A dica Did you mean: 'iter'? é o Python procurando um nome parecido (iter é uma função embutida); aqui ela não ajuda. Isso é uma vantagem, na verdade: a comprehension não deixa variáveis soltas pelo programa. Como consertar: se você precisa do último item, use compras[-1].

Parênteses no lugar dos colchetes
notas = [7.0, 4.5, 8.5]
aprovadas = (nota for nota in notas if nota >= 6)
print(aprovadas)
print(list(aprovadas))
$ python3 lc_parenteses.py
<generator object <genexpr> at 0x7fe7e2b0cee0>
[7.0, 8.5]

Sem erro, mas o print não mostrou uma lista: mostrou um gerador (generator), um objeto que vai produzindo os itens quando alguém pede, sem guardar todos de uma vez (o número depois do at é um endereço da memória e muda a cada execução). Com list() em volta, os itens aparecem. Geradores são muito úteis e têm aula própria: Geradores. Como consertar: para uma lista, colchetes: [nota for nota in notas if nota >= 6].

A lista de None

Você viu na seção 6: [print(item) for item in compras] mostra os itens e cria [None, None, None]. Se aparecer uma lista cheia de None, procure uma comprehension cuja expressão é uma função ou método que não devolve nada (print, append, sort…). Use um for comum.


Referência rápida

FormaO que fazExemplo
[expr for x in seq]Uma lista com expr calculada para cada x[n * n for n in range(4)] → [0, 1, 4, 9]
[x for x in seq if cond]Só os itens em que cond é verdadeira[n for n in notas if n >= 6]
[a if cond else b for x in seq]Para cada item, a ou b["ok" if n >= 6 else "rec" for n in notas]
[expr for x in seq if cond]Filtra e transforma[n + 1 for n in notas if n >= 6]
list(… for x in seq) / (… for x in seq)Gerador (não é lista até passar pelo list())Aula Geradores
SintomaCausa provável
SyntaxError: invalid syntax apontando o elseif/else no fim; com else, o if vai no começo
SyntaxError: expected 'else' after 'if' expressionif no começo sem else; para filtrar, o if vai no fim
Uma lista cheia de NoneA expressão é um print (ou outro que devolve None): use for
NameError com a variável da comprehensionEla só existe dentro dos colchetes
<generator object <genexpr> at 0x…>Parênteses no lugar dos colchetes

Exercícios

1. Complete a comprehension

Complete para criar a lista com o dobro de cada número:

dobros = [n * 2 n numeros]

2. O resultado

O que [n * 10 for n in range(3)] devolve? Escreva como o Python mostraria.

3. Só os baratos

Complete o filtro para ficarem só os preços menores que 10:

baratos = [p for p in precos p < 10]

4. Qual destas linhas está escrita certo?

5. Com notas = [8, 3, 9, 5], quantos itens tem [n for n in notas if n >= 6]?

6. Em qual destas situações o for comum é melhor que uma list comprehension?

Missão final: a situação da turma

Missão: a professora quer, para cada nota, a palavra "aprovado" (6 ou mais) ou "recuperação". O programa dá SyntaxError. Ponha o if/else no lugar certo.

notas = [7.0, 4.5, 8.5, 6.0, 9.5, 5.0]
situacao = ["aprovado" for nota in notas if nota >= 6 else "recuperação"]
print(situacao)
notas = [7.0, 4.5, 8.5, 6.0, 9.5, 5.0]
situacao = ["aprovado" if nota >= 6 else "recuperação" for nota in notas]
print(situacao)

Existe também a mesma ideia para dicionários e conjuntos, com chaves em vez de colchetes: a aula Dict e Set Comprehension mostra como.


Resumo

  • [expressão for item in lista] é o for + append em uma linha: cria uma lista nova e não mexe na original.
  • A expressão do começo diz o que entra; o for diz de onde vêm os itens.
  • if no fim, sem else: filtra (quem não passa fica de fora).
  • if/else no começo: escolhe um de dois valores para cada item (a lista tem o mesmo tamanho).
  • Não use para fazer coisas (print): você ganha uma lista de None. Não use quando ficar comprida ou precisar de break: o for é mais claro.
  • A variável da comprehension só existe dentro dos colchetes. Com parênteses, o resultado é um gerador, não uma lista.