Python Removendo Itens

No mercado, a Ana vai pondo os produtos no carrinho e riscando cada um da lista. Na cantina da escola, quem é atendido sai da fila. No fim do mês, a lista inteira vai para o lixo. Tirar itens de uma lista é tão comum quanto pôr, e o Python tem quatro jeitos de fazer isso, cada um para uma situação: remove(), pop(), del e clear().

Você vai aprender
  • A tirar um item pelo valor com remove(), e o que acontece com itens repetidos.
  • A tirar um item pelo índice com pop(), e a usar o item que ele devolve.
  • A apagar itens e fatias com del, e a esvaziar a lista com clear().
  • A tirar todas as ocorrências de um item.
  • Por que remover itens dentro de um for pula itens, e como fazer certo.
  • Os erros reais: o ValueError do remove e o IndexError do pop.

A ideia: riscar pelo nome ou pela posição

Há duas maneiras de dizer a alguém qual item riscar da lista:

  • Pelo nome: "risca o café". Você não sabe (nem precisa saber) em que posição ele está. É o remove("café").
  • Pela posição: "risca o primeiro", "risca o último". Você não liga para qual é o item. É o pop(0), o pop() e o del lista[0].

Em qualquer dos casos, os itens que vêm depois andam uma casa para a esquerda para ocupar o lugar vazio. A lista nunca fica com um "buraco".


1. remove(): tirar pelo valor

compras = ["arroz", "feijão", "café", "leite"]
compras.remove("café")
print(compras)
cesta = ["pão", "leite", "pão", "ovos", "pão"]
cesta.remove("pão")
print(cesta)
$ python3 remove.py
['arroz', 'feijão', 'leite']
['leite', 'pão', 'ovos', 'pão']
compras.remove("café")
"Lista de compras, remova o café". O Python procura o primeiro item igual a "café" e o tira. O leite, que estava no índice 3, passa para o 2.
cesta.remove("pão")
Com itens repetidos, o remove tira só o primeiro que encontrar. Sobraram dois pães.

Como o append (aula Adicionando Itens), o remove muda a própria lista e devolve None. Por isso a linha é só compras.remove("café"), sem =.

Tirando sem dar erro, e tirando todos

Se o item não estiver na lista, o remove para o programa com um erro (você vai vê-lo em Quando dá errado). O jeito seguro é perguntar antes com in. E, para tirar todas as ocorrências, repita enquanto o item ainda estiver lá:

compras = ["arroz", "feijão", "café", "leite"]
item = "açúcar"
if item in compras:
    compras.remove(item)
    print(f"{item} riscado.")
else:
    print(f"{item} não estava na lista.")
cesta = ["pão", "leite", "pão", "ovos", "pão"]
while "pão" in cesta:
    cesta.remove("pão")
print(cesta)
$ python3 remove_seguro.py
açúcar não estava na lista.
['leite', 'ovos']

O while "pão" in cesta: (aula while) remove um pão por volta e para quando não sobra nenhum. Funciona bem em listas pequenas como esta; para listas grandes, o jeito mais rápido é criar uma lista nova só com o que fica, como você vai ver na seção 5.

Missão: a Ana já pôs o sabão no carrinho. Use remove para riscá-lo da lista, antes do print.

compras = ["arroz", "feijão", "sabão", "leite"]

print(compras)
compras = ["arroz", "feijão", "sabão", "leite"]
compras.remove("sabão")
print(compras)

2. pop(): tirar pela posição (e ficar com o item)

O pop ("estourar", "tirar de uma vez") tem duas diferenças em relação ao remove: ele recebe o índice, e não o valor; e ele devolve o item que tirou, para você usar. Sem índice, ele tira o último.

>>> compras = ["arroz", "feijão", "café", "leite"]
>>> compras.pop()
'leite'
>>> compras
['arroz', 'feijão', 'café']
>>> compras.pop(1)
'feijão'
>>> compras
['arroz', 'café']

No modo interativo, o 'leite' que aparece logo depois de compras.pop() é o valor devolvido: o item que saiu. Depois, pop(1) tirou o item de índice 1, o feijão.

A fila da cantina

Uma fila é o exemplo perfeito: quem chegou primeiro é atendido primeiro (sai do começo, pop(0)), e o programa precisa saber quem está sendo atendido. É para isso que serve o valor devolvido:

fila = ["Ana", "Bruno", "Carla", "Davi"]
ultimo = fila.pop()
print(f"{ultimo} desistiu e saiu da fila.")
atendido = fila.pop(0)
print(f"Atendendo: {atendido}")
print(f"Ainda na fila: {fila}")
$ python3 fila.py
Davi desistiu e saiu da fila.
Atendendo: Ana
Ainda na fila: ['Bruno', 'Carla']
ultimo = fila.pop()
Tira o último (o Davi) e guarda o nome dele em ultimo. Aqui o = está certo: o pop, ao contrário do append e do remove, devolve algo útil.
atendido = fila.pop(0)
Tira o primeiro (a Ana). O Bruno passa a ser o índice 0.

Missão: a cantina vai atender duas pessoas, sempre a primeira da fila. Complete as duas linhas com fila.pop(0) no lugar dos "".

fila = ["Ana", "Bruno", "Carla"]
atendido = ""
print(f"Atendendo: {atendido}")
atendido = ""
print(f"Atendendo: {atendido}")
print(f"Ainda na fila: {fila}")
fila = ["Ana", "Bruno", "Carla"]
atendido = fila.pop(0)
print(f"Atendendo: {atendido}")
atendido = fila.pop(0)
print(f"Atendendo: {atendido}")
print(f"Ainda na fila: {fila}")

3. del: apagar pelo índice ou uma fatia

del (de delete, "apagar") não é um método: é uma palavra-chave do Python, escrita antes do que você quer apagar, sem ponto e sem parênteses. Ela apaga um item pelo índice, como o pop, mas não devolve nada. E apaga fatias inteiras:

compras = ["arroz", "feijão", "café", "leite", "sabão", "sal"]
del compras[0]
print(compras)
del compras[1:3]
print(compras)
del compras[-1]
print(compras)
compras.clear()
print(compras)
$ python3 del.py
['feijão', 'café', 'leite', 'sabão', 'sal']
['feijão', 'sabão', 'sal']
['feijão', 'sabão']
[]
del compras[0]
Apaga o item de índice 0, o arroz.
del compras[1:3]
Apaga a fatia dos índices 1 e 2 (café e leite), como você viu fatias em Acessando Itens.
del compras[-1]
Apaga o último, o sal.
compras.clear()
O método clear ("limpar") tira todos os itens. A lista continua existindo, só que vazia: [].

del sem índice apaga a variável

Cuidado com a diferença entre esvaziar a lista e apagar a variável:

>>> compras = ["arroz", "café"]
>>> del compras
>>> compras
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    compras
NameError: name 'compras' is not defined

del compras, sem colchetes, apaga o nome compras: depois disso, é como se a variável nunca tivesse existido (NameError). Para ter uma lista vazia e continuar usando, é compras.clear().


4. Qual usar?

Você sabe……e querUseSe não existir
O valor ("o café")Tirar a primeira ocorrêncialista.remove("café")ValueError
O valorTirar todas as ocorrênciaswhile x in lista: lista.remove(x) ou uma lista nova (seção 5)Não faz nada
A posiçãoTirar e usar o itemitem = lista.pop(i)IndexError
Nada (quer o último)Tirar e usar o últimoitem = lista.pop()IndexError se a lista estiver vazia
A posiçãoSó apagardel lista[i]IndexError
Um trechoApagar vários seguidosdel lista[a:b]Não dá erro
—Esvaziar tudolista.clear()—

5. Removendo dentro de um for: o item pulado

A professora quer tirar da lista todas as notas abaixo de 6. Parece simples: passar pelas notas e remover as baixas.

notas = [4.0, 5.5, 8.0, 3.0, 9.0, 7.5]
for nota in notas:
    if nota < 6:
        notas.remove(nota)
print(notas)
$ python3 notas_errado.py
[5.5, 8.0, 9.0, 7.5]

O 5.5 escapou, e nenhum erro apareceu. O que aconteceu? O for anda pela lista pelo índice: primeiro o 0, depois o 1, o 2…

  1. Volta 1, índice 0: a nota é 4.0. É menor que 6, então sai. A lista vira [5.5, 8.0, 3.0, 9.0, 7.5]: todo mundo andou uma casa para a esquerda, e o 5.5 agora está no índice 0.
  2. Volta 2, índice 1: o for segue em frente, para o índice 1, onde agora está o 8.0. O 5.5, que foi para o índice 0, nunca é olhado.
  3. Volta 3, índice 2: o 3.0. Sai. O 9.0 e o 7.5 andam para a esquerda.
  4. Volta 4, índice 3: o 7.5 (o 9.0 foi para o índice 2 e também foi pulado, mas ele não precisava sair).

É como riscar a lista de compras enquanto uma pessoa a reescreve sem os itens riscados: você perde o lugar. Dois jeitos certos:

notas = [4.0, 5.5, 8.0, 3.0, 9.0, 7.5]
for nota in notas[:]:
    if nota < 6:
        notas.remove(nota)
print(notas)
$ python3 notas_certo.py
[8.0, 9.0, 7.5]

O notas[:] é uma cópia da lista (uma fatia do começo ao fim, aula Copiando Listas). O for anda pela cópia, que não muda, e o remove tira os itens da original. Ninguém perde o lugar.

notas = [4.0, 5.5, 8.0, 3.0, 9.0, 7.5]
aprovadas = []
for nota in notas:
    if nota >= 6:
        aprovadas.append(nota)
print(aprovadas)
$ python3 notas_certo2.py
[8.0, 9.0, 7.5]

O segundo jeito pensa ao contrário: em vez de tirar as notas baixas, ele monta uma lista nova só com as que ficam. A lista original não muda durante o for, então nada é pulado. Este é o jeito mais usado (e o mais rápido em listas grandes), e na aula List Comprehension você vai escrevê-lo numa linha só.

Regra de ouro

Nunca tire (nem ponha) itens numa lista enquanto um for anda por essa mesma lista. Ande por uma cópia (for x in lista[:]) ou monte uma lista nova.


Quando dá errado

ValueError: remover o que não está na lista
compras = ["arroz", "feijão", "café", "leite"]
compras.remove("açúcar")
print(compras)
$ python3 remove_erro.py
Traceback (most recent call last):
  File "/home/ana/remove_erro.py", line 2, in <module>
    compras.remove("açúcar")
    ~~~~~~~~~~~~~~^^^^^^^^^^
ValueError: list.remove(x): x not in list

Linha por linha:

  • File "/home/ana/remove_erro.py", line 2: o erro foi na linha 2. O print da linha 3 não chegou a rodar.
  • Os ^^^^ marcam o ("açúcar"): o valor pedido é o problema.
  • ValueError: list.remove(x): x not in list: "erro de valor: list.remove(x): x não está na lista". O x quer dizer "o valor que você pediu"; a mensagem não repete qual era. É a mesma mensagem do index(), que você viu em Acessando Itens.

Lembre que a comparação é exata: remove("Café") ou remove("cafe") numa lista com "café" dão o mesmo erro. Como consertar: confira antes com if item in lista:, como no remove_seguro.py.

O índice no remove

A Ana queria tirar o primeiro item e escreveu remove(0):

>>> compras = ["arroz", "café"]
>>> compras.remove(0)
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    compras.remove(0)
    ~~~~~~~~~~~~~~^^^
ValueError: list.remove(x): x not in list

O remove não sabe nada de índices: ele procurou na lista um item igual ao número 0, e não havia nenhum. (Pior: numa lista de números, como [0, 5, 7], o remove(0) funcionaria, mas tiraria o valor 0, onde quer que ele estivesse.) Como consertar: pelo índice, use pop(0) ou del lista[0].

IndexError: o pop numa lista vazia ou num índice que não existe
fila = ["Ana"]
print(fila.pop(0))
print(fila.pop(0))
$ python3 fila_vazia.py
Ana
Traceback (most recent call last):
  File "/home/ana/fila_vazia.py", line 3, in <module>
    print(fila.pop(0))
          ~~~~~~~~^^^
IndexError: pop from empty list

O primeiro pop atendeu a Ana, e a fila ficou vazia. O segundo não tinha de onde tirar: pop from empty list, "pop de uma lista vazia". Com uma lista que tem itens, mas um índice grande demais, a mensagem muda um pouco:

>>> compras = ["arroz", "café"]
>>> compras.pop(10)
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    compras.pop(10)
    ~~~~~~~~~~~^^^^
IndexError: pop index out of range

Como consertar: antes de tirar, confira se ainda tem alguém: if fila: (uma lista vazia conta como falso, aula Booleanos) ou if len(fila) > 0:. Um laço que atende até a fila acabar fica assim: while fila: atendido = fila.pop(0).

Guardar o resultado do remove
>>> compras = ["arroz", "café"]
>>> item = compras.remove("arroz")
>>> print(item)
None

A Ana queria guardar o item que saiu, mas o remove devolve None (você já sabe qual é o item: foi você que o escreveu!). Só o pop devolve o item removido. E nunca escreva compras = compras.remove(…): a lista vira None, como o append da aula Adicionando Itens.

Itens pulados ao remover dentro do for

Você viu na seção 5: sem erro nenhum, o resultado sai errado. Se uma remoção "esqueceu" alguns itens, procure um remove, pop ou del dentro de um for que anda pela mesma lista.


Referência rápida

EscritaO que fazDevolve
lista.remove(x)Tira a primeira ocorrência do valor xNone
lista.pop()Tira o último itemO item tirado
lista.pop(i)Tira o item de índice iO item tirado
del lista[i]Apaga o item de índice i— (é uma instrução)
del lista[a:b]Apaga a fatia—
lista.clear()Tira todos os itens; a lista fica []None
del listaApaga a variável—
SintomaCausa provável
ValueError: list.remove(x): x not in listO valor não está na lista (maiúsculas, acentos?) ou passou um índice para o remove
IndexError: pop from empty listpop numa lista vazia: confira com if lista:
IndexError: pop index out of rangepop(i) com um índice que não existe
NameError: name 'compras' is not defined depois de um deldel compras apagou a variável; para esvaziar, clear()
Sobrou um item que deveria ter saídoRemoção dentro de um for na mesma lista, ou remove tirou só a primeira ocorrência
A variável vale NoneGuardou o resultado do remove ou do clear

Exercícios

1. Riscando pelo nome

Complete para tirar o leite da lista:

compras.("leite")

2. O último a sair

Complete para tirar o último item e guardá-lo em item:

item = compras.

3. Quanto sobrou?

Com cesta = ["pão", "pão", "ovos", "pão"], depois de cesta.remove("pão"), quantos pães ficam na cesta?

4. Qual destes tira o primeiro item e devolve o item tirado?

5. Depois de compras.clear(), o que print(compras) mostra?

6. Por que remover itens de uma lista dentro de um for que anda por ela mesma é perigoso?

Missão final: só as notas de aprovação

Missão: o programa deveria tirar todas as notas abaixo de 6, mas o 5.5 escapa. Conserte o laço (dica: faça o for andar por uma cópia, notas[:], ou monte uma lista nova só com as notas que ficam).

notas = [4.0, 5.5, 8.0, 3.0, 9.0, 7.5]
for nota in notas:
    if nota < 6:
        notas.remove(nota)
print(notas)
notas = [4.0, 5.5, 8.0, 3.0, 9.0, 7.5]
for nota in notas[:]:
    if nota < 6:
        notas.remove(nota)
print(notas)

Resumo

  • remove(x) tira pelo valor, só a primeira ocorrência; se não houver, ValueError. Pergunte antes com in.
  • pop(i) tira pelo índice e devolve o item; pop() tira o último. Lista vazia: IndexError.
  • del lista[i] e del lista[a:b] apagam pelo índice ou pela fatia; del lista apaga a variável.
  • clear() esvazia a lista, que continua existindo.
  • Os itens seguintes sempre andam para a esquerda: não fica buraco.
  • Para tirar todas as ocorrências: while x in lista: lista.remove(x), ou uma lista nova só com o que fica.
  • Nunca remova itens dentro de um for que anda pela mesma lista: ande por uma cópia (lista[:]) ou monte uma lista nova.