Python Adicionando Itens

A lista de compras nunca fica pronta de uma vez. A Ana abre o armário, vê que o café acabou e escreve "café" no fim da folha; a vizinha pede para ela trazer sal e óleo, e mais dois itens entram. Na aula Alterando Itens, você viu que compras[4] = "sabão" dá erro numa lista de 4 itens: a atribuição só troca o que já existe. Para acrescentar itens, a lista tem métodos próprios. É o assunto desta aula.

Você vai aprender
  • A pôr um item no fim com append().
  • A montar uma lista do zero, começando de [], inclusive com o que a pessoa digita.
  • A pôr um item numa posição escolhida com insert().
  • A juntar uma lista inteira à outra com extend(), + e +=, e a diferença entre elas.
  • Os erros reais: o append que devolve None (lista = lista.append(x)), o AttributeError de NoneType, o texto que vira letras soltas e o + com um texto.

A ideia: escrever no fim da folha

Quando a Ana lembra de um item novo, o jeito mais natural é escrevê-lo no fim da lista, embaixo do último. Às vezes, porém, ela quer encaixar um item no meio ("o pão tem de ser o primeiro, para eu não esquecer"). E às vezes recebe uma listinha inteira de outra pessoa para juntar à dela. São três situações, e cada uma tem o seu método:

SituaçãoMétodoTradução
Um item no fimappend(item)"anexar", "acrescentar no fim"
Um item numa posiçãoinsert(posição, item)"inserir"
Vários itens (outra lista) no fimextend(outra_lista)"estender"

Os três alteram a própria lista (ela é mutável, como você viu em Alterando Itens). Guarde essa frase: ela é a chave do erro mais famoso desta aula.


1. append(): um item no fim

compras = ["arroz", "feijão"]
print(compras)
compras.append("café")
print(compras)
compras.append("leite")
print(compras)
print(f"Agora são {len(compras)} itens.")
compras
A lista que vai receber o item.
.
O ponto: "da lista compras, use o método…". Métodos são funções que pertencem a um valor.
append
O método que acrescenta um item no fim.
("café")
Entre parênteses, o item novo. Exatamente um.
$ python3 append.py
['arroz', 'feijão']
['arroz', 'feijão', 'café']
['arroz', 'feijão', 'café', 'leite']
Agora são 4 itens.

A cada append, a lista ganhou um item no fim e o len aumentou 1. Repare que a linha compras.append("café") não tem =: ela não cria uma lista nova para guardar em algum lugar. Ela muda a lista compras que já existe.

Missão: use append duas vezes para acrescentar "leite" e depois "pão" à lista, antes do print.

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

print(compras)
compras = ["arroz", "feijão"]
compras.append("leite")
compras.append("pão")
print(compras)

2. Montando uma lista do zero

O uso mais comum do append é encher uma lista vazia, um item de cada vez. A Ana quer que o programa pergunte os itens e monte a lista para ela:

compras = []
for i in range(3):
    item = input("Item: ")
    compras.append(item)
print(compras)
$ python3 montar.py
Item: ovos
Item: pão
Item: leite
['ovos', 'pão', 'leite']
  1. compras = []: a lista começa vazia. Ela precisa existir antes do laço, senão não há onde fazer o append.
  2. O for i in range(3) (aula range()) repete o bloco 3 vezes.
  3. A cada volta, o input() lê um item e o append o põe no fim.
  4. Depois do laço, a lista tem os 3 itens, na ordem em que foram digitados.

E se a Ana não souber quantos itens vão ser? Um while com uma palavra para parar (aulas while e break e continue):

compras = []
while True:
    item = input("Item (ou fim): ")
    if item == "fim":
        break
    compras.append(item)
print(f"Sua lista tem {len(compras)} itens: {compras}")
$ python3 montar2.py
Item (ou fim): café
Item (ou fim): leite
Item (ou fim): fim
Sua lista tem 2 itens: ['café', 'leite']
$ python3 montar2.py
Item (ou fim): fim
Sua lista tem 0 itens: []

Na segunda vez, a Ana digitou fim logo de cara, e a lista ficou vazia, sem erro nenhum. Repare que o "fim" não entrou na lista: o break vem antes do append.


3. insert(): um item numa posição

Na fila da cantina, a Ana chegou primeiro e precisa entrar no começo; depois o Beto vai entrar no meio. O insert recebe dois valores: primeiro o índice onde o item vai ficar, depois o item.

fila = ["Bruno", "Carla", "Davi"]
fila.insert(0, "Ana")
print(fila)
fila.insert(2, "Beto")
print(fila)
fila.insert(100, "Zeca")
print(fila)
$ python3 insert.py
['Ana', 'Bruno', 'Carla', 'Davi']
['Ana', 'Bruno', 'Beto', 'Carla', 'Davi']
['Ana', 'Bruno', 'Beto', 'Carla', 'Davi', 'Zeca']
fila.insert(0, "Ana")
Põe a Ana no índice 0, o começo. Todos os outros andam uma casa para a direita: o Bruno, que era o 0, passa a ser o 1.
fila.insert(2, "Beto")
O Beto fica no índice 2, ou seja, antes de quem estava no 2 (a Carla).
fila.insert(100, "Zeca")
Um índice maior que a lista não dá erro: o item simplesmente vai para o fim, como num append.

Com um índice negativo, cuidado: insert(-1, item) não põe no fim. Ele põe antes do último, porque o item novo ocupa o índice -1 e empurra quem estava lá:

>>> compras = ["arroz", "feijão"]
>>> compras.append("café")
>>> print(compras.append("leite"))
None
>>> compras
['arroz', 'feijão', 'café', 'leite']
>>> compras.insert(-1, "sal")
>>> compras
['arroz', 'feijão', 'café', 'sal', 'leite']

O sal ficou entre o café e o leite. Para pôr no fim, use append. (E repare na terceira linha: print(compras.append("leite")) mostrou None, mas o leite entrou na lista. Guarde isso para o Quando dá errado.)

O insert(0, …) dá mais trabalho ao computador

Para pôr um item no começo, o Python precisa empurrar todos os outros uma casa para a direita. Numa lista de compras, isso não faz diferença nenhuma. Numa lista de um milhão de itens, fazer isso muitas vezes começa a pesar; o append, no fim, é sempre rápido. Quando precisar pôr e tirar coisas do começo o tempo todo, existe uma estrutura feita para isso, o deque (aula O Módulo collections).


4. Juntando listas: extend(), + e +=

A vizinha mandou a listinha dela: sal e óleo. A Ana quer juntar os itens dela à lista de compras.

compras = ["arroz", "feijão"]
da_vizinha = ["sal", "óleo"]
compras.extend(da_vizinha)
print(compras)
print(da_vizinha)
$ python3 extend.py
['arroz', 'feijão', 'sal', 'óleo']
['sal', 'óleo']

O extend acrescentou, no fim de compras, cada um dos itens de da_vizinha. A lista da vizinha ficou como estava.

append de uma lista: a lista dentro da lista

E se a Ana usar append com a lista da vizinha?

compras = ["arroz", "feijão"]
compras.append(["sal", "óleo"])
print(compras)
print(len(compras))
$ python3 append_lista.py
['arroz', 'feijão', ['sal', 'óleo']]
3

Repare nos colchetes de dentro: o append põe um item no fim, e esse item foi a lista inteira da vizinha. A lista ficou com 3 itens, e o terceiro é uma lista (você viu listas dentro de listas em Acessando Itens). Às vezes é isso mesmo que você quer; quase sempre, quem escreve isso queria o extend.

Com compras = ["arroz", "feijão"]ResultadoItens
compras.append(["sal", "óleo"])['arroz', 'feijão', ['sal', 'óleo']]3
compras.extend(["sal", "óleo"])['arroz', 'feijão', 'sal', 'óleo']4

O + e o +=

Como nos textos (aula Juntar e Repetir Textos), o + junta duas listas. Mas há uma diferença importante: o + cria uma lista nova e deixa as duas originais em paz. Já o += muda a lista da esquerda, como o extend.

>>> compras = ["arroz", "feijão"]
>>> nova = compras + ["sal", "óleo"]
>>> nova
['arroz', 'feijão', 'sal', 'óleo']
>>> compras
['arroz', 'feijão']
>>> compras += ["pão"]
>>> compras
['arroz', 'feijão', 'pão']
  • nova = compras + ["sal", "óleo"]: a lista nova tem os 4 itens; compras continua com 2. O + não mexeu em ninguém.
  • compras += ["pão"]: agora sim compras mudou. O += em listas funciona como o extend. Do lado direito, uma lista (por isso ["pão"], com colchetes).

Repetindo: *

Outro operador que vem dos textos: [0] * 3 é uma lista com o 0 repetido 3 vezes. É um jeito rápido de criar o placar de um jogo com três jogadores, todos começando do zero:

>>> placar = [0] * 3
>>> placar
[0, 0, 0]

Formas diferentes de adicionar

Você querEscrevaMuda a lista?
Um item no fimlista.append(item)Sim. É o jeito mais usado
Um item numa posiçãolista.insert(i, item)Sim. Os outros andam para a direita
Os itens de outra lista, no fimlista.extend(outra)Sim
O mesmo, mais curtolista += outraSim. Igual ao extend
Uma lista nova com as duas juntasnova = lista + outraNão: as duas continuam como estavam
Um item no fim, criando uma lista novanova = lista + [item]Não
Uma lista com um valor repetido[0] * nCria uma lista nova

Quando dá errado

lista = lista.append(x): a lista vira None

Este é, de longe, o erro mais comum com listas. A Ana se acostumou a escrever nome = nome.upper() com textos e fez o mesmo com o append:

compras = ["arroz", "feijão"]
compras = compras.append("café")
print(compras)
compras.append("leite")
$ python3 none.py
None
Traceback (most recent call last):
  File "/home/ana/none.py", line 4, in <module>
    compras.append("leite")
    ^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'append'

Vamos por partes:

  • Linha 2: o append acrescentou o café na lista e devolveu None, o valor que quer dizer "nada" (aula O Valor None). Métodos que alteram a lista não devolvem a lista: eles fazem o trabalho e devolvem None. Você viu isso lá em cima, no print(compras.append("leite")). O compras = … guardou esse None na variável, e a lista (que tinha arroz, feijão e café) ficou sem nome nenhum, perdida.
  • Linha 3: o print mostrou None. Nenhum erro ainda, mas a lista já se foi.
  • Linha 4: compras agora vale None, e None não tem o método append. A mensagem AttributeError: 'NoneType' object has no attribute 'append' quer dizer "erro de atributo: um objeto do tipo NoneType (o tipo do None) não tem o atributo append". Os ^^^^ marcam compras.append.

Repare que o erro aparece numa linha depois da linha culpada. Quando você vir 'NoneType' object has no attribute …, a pergunta é: "onde essa variável recebeu None?". Quase sempre, foi um x = x.append(…), x = x.sort() ou parecido.

Como consertar: chame o método sozinho, sem =: compras.append("café").

Por que com textos é diferente?

Textos são imutáveis: nome.upper() não pode mudar o texto que está em nome, então ele devolve um texto novo, e você precisa guardá-lo (nome = nome.upper()). Listas são mutáveis: compras.append(x) muda a própria lista e não tem nada novo para devolver. Regra prática: método de lista que altera (append, insert, extend, sort, reverse, remove, clear) devolve None; nunca guarde o resultado deles na própria lista.

O mesmo erro dentro de um laço

No laço, o erro aparece na segunda volta, o que deixa tudo mais confuso:

compras = []
for i in range(3):
    item = input("Item: ")
    compras = compras.append(item)
print(compras)
$ python3 none2.py
Item: ovos
Item: pão
Traceback (most recent call last):
  File "/home/ana/none2.py", line 4, in <module>
    compras = compras.append(item)
              ^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'append'

Na primeira volta, o append funcionou (a lista vazia recebeu os ovos) e devolveu None, que foi guardado em compras. Na segunda volta, compras já era None, e o append do pão quebrou. Você vai consertar isso na missão final.

Um texto no extend ou no +=: letras soltas
>>> compras.extend("óleo")
>>> compras
['arroz', 'feijão', 'café', 'sal', 'leite', 'ó', 'l', 'e', 'o']

Nenhum erro, e o óleo virou quatro itens: 'ó', 'l', 'e', 'o'. O extend acrescenta cada item do que recebe, e os itens de um texto são as letras. O += faz o mesmo:

>>> compras = ["arroz", "feijão", "pão"]
>>> compras += "sal"
>>> compras
['arroz', 'feijão', 'pão', 's', 'a', 'l']

Como consertar: para um item, append("óleo"). Para usar extend ou +=, ponha o texto dentro de uma lista: compras += ["sal"].

+ com um texto

Curiosamente, o + (sem o =) não aceita o texto e avisa:

>>> compras = ["arroz", "feijão", "pão"]
>>> compras + "sal"
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    compras + "sal"
    ~~~~~~~~^~~~~~~
TypeError: can only concatenate list (not "str") to list

"Erro de tipo: só dá para concatenar (juntar) uma lista a outra lista, e não um str". O ^ embaixo do + mostra a operação que falhou, e os ~ os dois lados dela. Como consertar: compras + ["sal"].

Dois itens num append só, ou um método que não existe
>>> compras.append("ovos", "farinha")
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    compras.append("ovos", "farinha")
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
TypeError: list.append() takes exactly one argument (2 given)
>>> compras.push("ovos")
Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
    compras.push("ovos")
    ^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'push'
  • list.append() takes exactly one argument (2 given): "o append recebe exatamente um argumento (foram dados 2)". Para dois itens, dois append, ou compras.extend(["ovos", "farinha"]).
  • 'list' object has no attribute 'push': em outras linguagens (como o JavaScript), acrescentar no fim se chama push. No Python, é append. O mesmo vale para add, que é dos conjuntos (aula Conjuntos), não das listas.

Referência rápida

EscritaO que fazDevolve
lista.append(x)Põe x no fimNone
lista.insert(i, x)Põe x no índice i; quem estava lá anda para a direita. Índice grande demais = no fimNone
lista.extend(outra)Põe cada item de outra no fim (um texto vira letras)None
lista += outraO mesmo que extend—
lista + outraCria uma lista nova com as duas; não muda nenhumaA lista nova
[x] * nUma lista nova com x repetido n vezesA lista nova
SintomaCausa provável
A lista virou Nonelista = lista.append(x) (ou insert, extend…): chame sem =
AttributeError: 'NoneType' object has no attribute 'append'A variável recebeu None numa linha anterior, quase sempre pelo motivo acima
Letras soltas como itensTexto no extend ou no +=; use append ou ponha o texto numa lista
Uma lista dentro da listaappend de uma lista; para juntar os itens, extend
TypeError: can only concatenate list (not "str") to listlista + "texto"; use lista + ["texto"]
TypeError: list.append() takes exactly one argument (2 given)Dois itens num append
AttributeError: 'list' object has no attribute 'push' (ou 'add')O nome certo é append
O item entrou antes do últimoinsert(-1, x); para o fim, append(x)

Exercícios

1. No fim da lista

Complete o método que põe o açúcar no fim da lista:

compras.("açúcar")

2. Primeiro da fila

Complete para pôr a Eva no começo da fila:

fila.insert(, "Eva")

3. Quantos itens?

Com a = [1, 2], depois de a.append([3, 4]), quanto vale len(a)?

4. Depois de compras = ["arroz"] e compras = compras.append("feijão"), quanto vale compras?

5. Qual destas linhas deixa a = [1, 2] como [1, 2] e cria uma lista nova [1, 2, 3]?

6. O que letras = ["a"] seguido de letras.extend("bc") deixa em letras?

Missão final: a lista pelo teclado

Missão: o programa deveria perguntar 3 itens e mostrar a lista, mas quebra com AttributeError na segunda pergunta. Conserte a linha do append. (O editor vai digitar ovos, pão e leite por você.)

compras = []
for i in range(3):
    item = input("Item: ")
    compras = compras.append(item)
print(compras)
compras = []
for i in range(3):
    item = input("Item: ")
    compras.append(item)
print(compras)

Resumo

  • append(x) põe um item no fim; é o jeito mais usado de encher uma lista que começou com [].
  • insert(i, x) põe o item no índice i; os outros andam para a direita. insert(-1, x) põe antes do último.
  • extend(outra) e += põem os itens de outra lista no fim; append de uma lista põe a lista inteira como um item só.
  • lista + outra cria uma lista nova e não muda nenhuma das duas.
  • Os métodos que alteram a lista devolvem None: nunca escreva lista = lista.append(x).
  • 'NoneType' object has no attribute 'append' quer dizer que a variável recebeu None antes; procure o = com um método de lista.
  • Texto no extend ou no += vira letras soltas.