Python Alterando Itens
A Ana chegou no mercado e lembrou que, em casa, ninguém toma café com açúcar. Ela não joga a lista de compras fora: pega a caneta, risca "café" e escreve "café sem açúcar" no mesmo lugar. As listas do Python deixam você fazer exatamente isso: trocar o valor de um item, sem mexer nos outros e sem criar uma lista nova. Nesta aula, você aprende a trocar um item, um pedaço da lista e todos os itens de uma vez.
- A trocar um item com
lista[índice] = novo_valor. - A fazer contas com um item:
estoque[0] -= 1. - A achar um item pelo valor e trocá-lo (
index()+ atribuição). - A trocar uma fatia inteira, até por uma de outro tamanho.
- A alterar todos os itens com
forerange(len(…)), e por que oforsozinho não altera nada. - Por que dá para trocar um item de uma lista, mas não uma letra de um texto.
- Os erros reais:
IndexErrorna atribuição, o==que não troca nada, e a fatia que recebe um texto.
A ideia: riscar e escrever no mesmo lugar
Na aula Acessando Itens, você usou compras[2] para ler o item do armário número 2. Para trocar o que tem dentro desse armário, você usa o mesmo endereço, só que do lado esquerdo do =, exatamente como numa variável comum:
| Escrita | O que acontece |
|---|---|
x = compras[2] | Lê o item 2 e guarda o valor em x. A lista não muda. |
compras[2] = x | Troca o item 2 pelo valor de x. O valor que estava lá antes some. |
Isso só é possível porque a lista é mutável (em inglês, mutable, "que pode mudar"): depois de criada, o conteúdo dela pode ser alterado. Nem todo tipo do Python é assim, como você vai ver na seção 5.
1. Trocando um item
compras = ["arroz", "feijão", "café", "leite"]
print("Antes: ", compras)
compras[2] = "café sem açúcar"
compras[-1] = "leite desnatado"
print("Depois:", compras)
- compras[2]
- O armário de índice 2 (o terceiro item, o café). Do lado esquerdo do
=, ele é o lugar onde o novo valor vai ser guardado. - =
- A atribuição de sempre: "guarde o valor da direita no lugar da esquerda".
- "café sem açúcar"
- O valor novo. Ele ocupa o lugar do antigo; o
"café"deixa de existir na lista. - compras[-1]
- Índices negativos também valem para trocar: aqui, o último item.
$ python3 trocar.py Antes: ['arroz', 'feijão', 'café', 'leite'] Depois: ['arroz', 'feijão', 'café sem açúcar', 'leite desnatado']
Repare no que não mudou: a lista continua com 4 itens, o arroz e o feijão continuam nos seus lugares, e a ordem é a mesma. Só os dois armários que você indicou receberam um conteúdo novo. (O espaço a mais em "Antes: " é só para as duas listas ficarem alinhadas na saída.)
Missão: troque o "café" da lista por "café descafeinado", com uma linha de atribuição antes do print (não reescreva a lista toda).
compras = ["arroz", "feijão", "café", "leite"] print(compras)
compras = ["arroz", "feijão", "café", "leite"] compras[2] = "café descafeinado" print(compras)
2. Fazendo contas com um item
A Ana também controla o estoque da lojinha numa lista: quantas unidades ela tem de cada produto. Vendeu uma unidade? O item diminui 1. Chegou mercadoria? Aumenta.
estoque = [12, 5, 30] print(estoque) estoque[1] = estoque[1] - 1 estoque[0] -= 2 estoque[2] += 10 print(estoque)
$ python3 estoque.py [12, 5, 30] [10, 4, 40]
- estoque[1] = estoque[1] - 1
- Leia da direita para a esquerda: o Python lê o item 1 (5), faz a conta (5 − 1 = 4) e guarda o resultado de volta no item 1.
- estoque[0] -= 2
- A forma curta da mesma coisa (aula Operadores de Atribuição): "tire 2 do item 0". De 12 foi para 10.
- estoque[2] += 10
- "Some 10 ao item 2": de 30 para 40.
3. Achando o item pelo valor e trocando
Nem sempre você sabe o índice. A Ana quer trocar o "feijão" por "feijão preto", mas não lembra em que posição ele está. Juntando o que você aprendeu: primeiro pergunta se ele está lá (in), depois descobre o índice (index()), e só então troca:
compras = ["arroz", "feijão", "café", "leite"]
velho = "feijão"
novo = "feijão preto"
if velho in compras:
posicao = compras.index(velho)
compras[posicao] = novo
print(f"Troquei {velho} por {novo} na posição {posicao}.")
print(compras)
$ python3 achar_trocar.py Troquei feijão por feijão preto na posição 1. ['arroz', 'feijão preto', 'café', 'leite']
Sem o if velho in compras:, um item que não está na lista faria o index() parar o programa com ValueError (você viu esse erro em Acessando Itens). E lembre: o index() acha só a primeira ocorrência. Se o feijão aparecesse duas vezes, só o primeiro seria trocado.
4. Trocando uma fatia
Você pode trocar um pedaço da lista de uma vez: do lado esquerdo do = vai uma fatia (aula Acessando Itens), e do lado direito, uma lista com os itens novos.
>>> compras = ["arroz", "feijão", "café", "leite"] >>> compras[1:3] = ["macarrão", "molho"] >>> compras ['arroz', 'macarrão', 'molho', 'leite']
Os itens dos índices 1 e 2 (feijão e café) saíram, e os dois novos entraram no lugar deles. E se a quantidade for diferente? A fatia aceita: a lista cresce ou encolhe para caber.
>>> compras[1:2] = ["batata", "cenoura", "chuchu"] >>> compras ['arroz', 'batata', 'cenoura', 'chuchu', 'molho', 'leite'] >>> len(compras) 6 >>> compras[1:4] = ["legumes"] >>> compras ['arroz', 'legumes', 'molho', 'leite']
compras[1:2] = [...três itens...]: saiu um item (o macarrão, índice 1) e entraram três. A lista passou de 4 para 6 itens.compras[1:4] = ["legumes"]: saíram três (batata, cenoura e chuchu) e entrou um. Voltou para 4.
Trocar fatias de tamanhos diferentes é poderoso, mas fica difícil de ler: quem olha compras[1:4] = ["legumes"] precisa parar e contar. Para acrescentar ou tirar itens, existem jeitos mais claros, com nomes que dizem o que fazem: Adicionando Itens e Removendo Itens.
5. Lista muda, texto não
Se a lista deixa trocar um item, será que um texto deixa trocar uma letra? A Ana digitou o nome em minúsculas e quer a primeira letra maiúscula:
nome = "ana" nome[0] = "A" print(nome)
$ python3 texto_imutavel.py
Traceback (most recent call last):
File "/home/ana/texto_imutavel.py", line 2, in <module>
nome[0] = "A"
~~~~^^^
TypeError: 'str' object does not support item assignment
"Erro de tipo: o objeto str não aceita atribuição de item". Os textos (str) são imutáveis: depois de criados, não mudam. Dá para ler nome[0], mas não trocar. Para "mudar" um texto, você cria um texto novo e guarda na variável: nome = "A" + nome[1:], ou nome = nome.capitalize() (aula Métodos de Texto).
Lista (list) | Texto (str) | |
|---|---|---|
Ler um item: x[0] | Pode | Pode |
Fatiar: x[1:3] | Pode | Pode |
Trocar um item: x[0] = … | Pode (mutável) | Não pode (imutável): TypeError |
Essa diferença entre mutável e imutável explica muitas surpresas do Python; ela tem uma aula só para ela: Mutável × Imutável.
6. Alterando todos os itens
A professora vai dar meio ponto a mais para a turma toda. A primeira ideia é passar pelas notas com um for e somar 0.5 em cada uma:
notas = [7.0, 8.5, 6.0, 9.5]
for nota in notas:
nota = nota + 0.5
print(notas)
$ python3 nota_errada.py [7.0, 8.5, 6.0, 9.5]
Nada mudou, e nenhum erro apareceu. Por quê? A cada volta, o for põe na variável nota o valor do item da vez (7.0, depois 8.5…). A linha nota = nota + 0.5 calcula um valor novo e o guarda na variável nota, e só nela; o armário da lista continua com o valor antigo, e a lista nem fica sabendo. É como a Ana anotar a nota nova num papelzinho e não passar a limpo no diário.
Para mudar a lista, você precisa escrever no armário dela, notas[i] = …, e para isso precisa do índice. O range(len(notas)) (aula range()) dá exatamente os índices: 0, 1, 2, 3.
notas = [7.0, 8.5, 6.0, 9.5]
for i in range(len(notas)):
notas[i] = notas[i] + 0.5
print(notas)
$ python3 nota_certa.py [7.5, 9.0, 6.5, 10.0]
- len(notas)
- 4, o número de notas.
- range(len(notas))
- Os números 0, 1, 2, 3: os índices válidos da lista.
- for i in …
- A cada volta,
ié um índice. O nomei(de "índice") é um costume muito comum para isso. - notas[i] = notas[i] + 0.5
- Lê o item
i, soma 0.5 e guarda de volta no itemi. Agora sim a lista muda.
Existe também um jeito de criar uma lista nova com todos os valores transformados, em uma linha só: a List Comprehension. E a aula Percorrendo uma Lista mostra o enumerate(), que dá o índice e o item ao mesmo tempo.
Formas diferentes de alterar
| Você quer | Escreva | Observação |
|---|---|---|
| Trocar o item de um índice que você conhece | lista[i] = novo | O jeito básico; o índice tem de existir |
| Fazer uma conta com um item | lista[i] += 1 | Igual a lista[i] = lista[i] + 1, mais curto |
| Trocar um item pelo valor | if velho in lista: + lista[lista.index(velho)] = novo | Troca só a primeira ocorrência |
| Trocar vários itens seguidos | lista[a:b] = [x, y] | Do lado direito, sempre uma lista; pode mudar o tamanho |
| Alterar todos os itens | for i in range(len(lista)): + lista[i] = … | Muda a própria lista. for item in lista: item = … não muda |
| Ter uma lista nova com tudo transformado | [x + 0.5 for x in lista] | A lista original fica como estava (aula List Comprehension) |
Quando dá errado
A Ana quer acrescentar o sabão no fim da lista e pensou: "a lista tem 4 itens, então o próximo é o índice 4":
compras = ["arroz", "feijão", "café", "leite"] compras[4] = "sabão" print(compras)
$ python3 atribuir_fora.py
Traceback (most recent call last):
File "/home/ana/atribuir_fora.py", line 2, in <module>
compras[4] = "sabão"
~~~~~~~^^^
IndexError: list assignment index out of range
Linha por linha:
File "/home/ana/atribuir_fora.py", line 2: o problema está na linha 2.- As marcas
~~~~~~~^^^apontam paracompras[4]: o lugar onde a Ana tentou guardar o valor. IndexError: list assignment index out of range: "erro de índice: índice da atribuição fora do intervalo". Repare na palavra assignment ("atribuição"): ao ler um índice que não existe, a mensagem élist index out of range; ao escrever, é esta.
A atribuição só troca o que já existe: os armários são 0, 1, 2 e 3, e não aparece um armário novo só porque você escreveu num número a mais. Como consertar: para pôr um item no fim, use compras.append("sabão"), que é o assunto da próxima aula, Adicionando Itens.
== no lugar de =: nada muda e nada reclama
compras = ["arroz", "feijão", "café", "leite"] compras[1] == "lentilha" print(compras)
$ python3 igual_duplo.py ['arroz', 'feijão', 'café', 'leite']
O feijão continua lá. Com dois sinais de igual, a linha 2 não é uma troca: é uma pergunta ("o item 1 é igual a lentilha?", aula Comparações). O Python responde False e joga a resposta fora, porque ninguém a guardou nem mostrou. No modo interativo dá para ver a resposta que se perdeu:
>>> compras[1] == "lentilha" False
Como consertar: para trocar, um sinal de igual: compras[1] = "lentilha". Regra para lembrar: = guarda, == pergunta.
A Ana queria trocar o primeiro item por "uva", mas usou uma fatia e esqueceu os colchetes do lado direito:
>>> compras = ["arroz", "legumes", "molho", "leite"] >>> compras[0:1] = "uva" >>> compras ['u', 'v', 'a', 'legumes', 'molho', 'leite']
Nenhum erro, e a uva virou três itens: 'u', 'v' e 'a'. A fatia espera do lado direito uma sequência de itens, e um texto é uma sequência de letras; então cada letra virou um item (como no list("uva") da aula Listas). Com um número, que não é uma sequência, aí sim vem um erro:
>>> compras[0:1] = 5
Traceback (most recent call last):
File "<python-input-3>", line 1, in <module>
compras[0:1] = 5
~~~~~~~^^^^^
TypeError: must assign iterable to extended slice
"É preciso atribuir um iterável (algo com vários itens) à fatia". Como consertar: para trocar um item só, use o índice, sem fatia: compras[0] = "uva". Se for mesmo uma fatia, ponha a lista do lado direito: compras[0:1] = ["uva"].
for que "altera" e não altera
Você viu na seção 6: for nota in notas: nota = nota + 0.5 roda sem erro e deixa a lista igualzinha. Se a lista "não mudou" depois de um for, procure uma linha que atribui à variável do laço (nota = …) em vez de ao item da lista (notas[i] = …).
Referência rápida
| Escrita | O que faz |
|---|---|
lista[i] = valor | Troca o item de índice i (que tem de existir) por valor |
lista[-1] = valor | Troca o último item |
lista[i] += n / -= / *= | Faz a conta com o item e guarda de volta |
lista[lista.index(velho)] = novo | Troca a primeira ocorrência de velho (erro se não houver) |
lista[a:b] = [x, y, …] | Troca os itens de a até antes de b pelos novos; a lista pode crescer ou encolher |
for i in range(len(lista)): lista[i] = … | Altera todos os itens da própria lista |
| Sintoma | Causa provável |
|---|---|
IndexError: list assignment index out of range | Atribuiu a um índice que não existe (para acrescentar no fim, use append) |
| A lista não mudou, sem erro | == no lugar de =, ou atribuição à variável do for |
| Apareceram letras soltas como itens | Atribuiu um texto a uma fatia: lista[0:1] = "uva" |
TypeError: must assign iterable to extended slice | Atribuiu um número (ou outro valor sem itens) a uma fatia |
TypeError: 'str' object does not support item assignment | Tentou trocar uma letra de um texto; textos são imutáveis |
Exercícios
1. Trocando o primeiro
Complete para trocar o primeiro aluno da lista por "Ana Paula":
2. Vendi duas
Complete o operador para tirar 2 unidades do item 0 do estoque:
3. Quantos itens?
Com lista = [1, 2, 3, 4, 5], depois de lista[1:4] = [0], quanto vale len(lista)?
4. A lista compras tem 3 itens. O que acontece com compras[3] = "sal"?
5. Depois de precos = [10, 20] e for p in precos: p = p * 2, quanto vale precos?
6. Qual destes dá erro?
Missão final: meio ponto para a turma
Missão: a professora quer somar 0.5 em todas as notas, mas o programa mostra a lista sem mudança nenhuma. Conserte o laço para ele alterar a própria lista (dica: range(len(notas)) e notas[i]).
notas = [7.0, 8.5, 6.0, 9.5]
for nota in notas:
nota = nota + 0.5
print(notas)
notas = [7.0, 8.5, 6.0, 9.5]
for i in range(len(notas)):
notas[i] = notas[i] + 0.5
print(notas)
Resumo
- Listas são mutáveis:
lista[i] = novotroca um item no lugar, sem mexer nos outros. - Do lado direito do
=,lista[i]lê; do lado esquerdo, escreve. - Contas com um item:
estoque[0] -= 1. - Para trocar pelo valor:
inpara conferir,index()para achar, atribuição para trocar. lista[a:b] = [...]troca uma fatia, até por outra de tamanho diferente. Do lado direito, sempre uma lista.- Atribuir a um índice que não existe dá
IndexError: a atribuição não aumenta a lista. for item in lista: item = …não altera a lista; usefor i in range(len(lista)): lista[i] = ….- Textos são imutáveis:
nome[0] = "A"dáTypeError.