Listas#
Ao longo do capítulo anterior, surgiu uma outra estrutura de dados básica: listas. Vamos entrar mais em detalhes nesta estrutura ao longo deste capítulo.
Definição#
Listas são um dos tipos de dados mais fundamentais e versáteis em Python. Uma lista é uma sequência ordenada de elementos que pode conter uma variedade de tipos de dados, como números, strings, outras listas, objetos, e mais. As listas em Python são mutáveis, o que significa que seus elementos podem ser alterados após a sua criação.
As listas possuem as seguintes caracterísicas:
Ordenadas: As listas mantêm a ordem dos elementos conforme são adicionados.
Mutáveis: Diferente de alguns outros tipos de coleções que vamos ver na sequência, como tuplas, as listas podem ser modificadas após a sua criação. Você pode adicionar, remover ou alterar seus elementos.
Permite duplicatas: Listas podem conter elementos duplicados. Cada elemento na lista mantém sua própria posição e pode ser acessado individualmente.
Heterogêneas: Uma lista pode conter elementos de diferentes tipos de dados. Por exemplo, você pode ter uma lista que contém números, strings e até mesmo outras listas.
Sintaxe básica#
O exemplo mais simples é uma lista de inteiros, conforme vimos no capítulo anterior, no terceiro exemplo da seção reforço prático - métodos vs funções.
lista_de_numeros = [10, 50, 40, 65, 90, 70, 30, 156]
print(lista_de_numeros)
[10, 50, 40, 65, 90, 70, 30, 156]
Uma lista é criada com colchetes ([ ]
), cada elemento é separado por vírgula (,
) e não necessariamente todos os elementos precisam ser do mesmo tipo.
lista_heterogenea = [10, 25.1, "um texto qualquer", True]
print(lista_heterogenea)
[10, 25.1, 'um texto qualquer', True]
Acessando elementos#
Cada elemento tem uma posição (ou índice) na lista começando do índice 0 para o primeiro elemento.
lista_acesso_elementos = [1, "Olá", 3.14, True]
# Acessando elementos da lista
print(lista_acesso_elementos[0])
print(lista_acesso_elementos[1])
1
Olá
Vimos fatiamento de sequencias no capítulo sobre strings, na seção indexação de strings, lembra? É possível usar o fatiamento em listas da mesma forma. Podemos usar exatamente a mesma sintaxe variavel[start:stop:step]
, com exatamente as mesmas características. Caso queira relembrar o conteúdo, retorne ao capítulo sobre fatiamento de strings.
Aqui vamos abordar apenas o caso que é diferente de strings, no qual temos uma lista de listas.
lista_de_listas = [[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]
Vamos começar com uma pergunta:
Quandos elementos tem a lista acima? Pense primeiro e clique para ver a resposta…
Resposta correta: 4 elementos. Execute o código abaixo para conferir.
lista_de_listas = [[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]
print(len(lista_de_listas))
Porque? Se você contou apenas os números de 1 a 10, talvez você não tenha entendido o conceito de listas. Vamos detalhar mais.
Reparem que a variável acima começa com [[
e termina com ]]
. A lista mais externa contém outras listas internas. Listas de listas também são chamadas de listas aninhadas. É como se tivéssemos vários «níveis» de listas, indo por camadas.
lista_de_listas = [[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]
print(f"Primeiro elemento da lista: {lista_de_listas[0]}")
print(f"Segundo elemento da lista: {lista_de_listas[1]}")
print(f"Terceiro elemento da lista: {lista_de_listas[2]}")
print(f"Quarto elemento da lista: {lista_de_listas[3]}")
Primeiro elemento da lista: [1]
Segundo elemento da lista: [2, 3]
Terceiro elemento da lista: [4, 5, 6]
Quarto elemento da lista: [7, 8, 9, 10]
O caso mais simples que consigo trazer pra representar listas aninhadas é lista = [primeiro_elemento, segundo_elemento, terceiro_elemento, quarto_elemento]
onde cada _elemento
é também uma lista! Pode parecer confuso, mas creio que este exemplo ajude a esclarecer.
Métodos de listas#
Diferentemente de string, listas tem relativamente poucos métodos, 11 no total, conforme consta na documentação oficial dos métodos de lista. Por este motivo, é possível cobrí-los todos aqui.
Adição de elementos#
Existem 3 métodos para trabalhar com adição de elementos à uma lista:
append( )
: Adiciona um item ao final da lista.extend( )
: Adiciona todos os itens de uma outra sequencia ao final da lista.insert( )
: Insere um item em uma posição específica.
Vamos ver em detalhes cada um deles.
append
#
O método append(x)
adiciona um dado objeto x
ao final da lista.
frutas = ["maçã", "banana", "laranja"]
frutas.append("uva")
print(frutas)
['maçã', 'banana', 'laranja', 'uva']
Notem que o objeto como um todo, no caso a string uva
, foi adicionada como um objeto único (uma única string) ao final da lista.
extend
#
O método extend(x)
estende a lista adicionando todos os itens, um a um, de uma outra sequencia. Ele funciona diferente do método append(x)
que adiciona o objeto inteiro.
frutas = ["maçã", "banana"]
outras_frutas = ["laranja", "uva"]
frutas.extend(outras_frutas)
print(frutas)
['maçã', 'banana', 'laranja', 'uva']
No exemplo, outras_frutas
é uma segunda lista, e os elementos desta listas, laranja
e uva
, são adicionados à lista frutas
. O extend
meio que varre uma dada sequencia, e adiciona os elementos um a um na lista.
Vamos entender melhor com mais um exemplo. Se no exemplo do append()
nós só trocássemos pelo extend()
, veja o que aconteceria:
frutas = ["maçã", "banana", "laranja"]
frutas.extend("uva")
print(frutas)
['maçã', 'banana', 'laranja', 'u', 'v', 'a']
Relembrando que uma string é uma sequencia também, só que de caracteres. Quando passamos a string uva
para o extend
em frutas.extend("uva")
, o que estamos dizendo é: pegue cada elemento (caracter) da string uva
e adicione um a um à lista frutas
.
É diferente do método append
que em frutas.append("uva")
nós estamos dizendo: adicione a string inteira uva
como um objeto único ao final da lista.
Conseguiram compreender tal diferença?
Como o extend
necessariamente varre uma sequência, não é possível estender uma lista a partir de algo que não seja uma sequência, gerando o erro abaixo
lista_de_numeros = [1, 2, 3, 4, 5]
lista_de_numeros.extend(6)
print(lista_de_numeros)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[9], line 2
1 lista_de_numeros = [1, 2, 3, 4, 5]
----> 2 lista_de_numeros.extend(6)
3 print(lista_de_numeros)
TypeError: 'int' object is not iterable
O erro TypeError: 'int' object is not iterable
informa justamente que o tipo int
proveniente do 6
passado para o extend
não é uma sequência.
Já o append
não precisa necessariamente receber uma sequência, pois ele adiciona o objeto em si, e não os elementos de uma dada sequência.
lista_de_numeros = [1, 2, 3, 4, 5]
lista_de_numeros.append(6)
print(lista_de_numeros)
[1, 2, 3, 4, 5, 6]
Para finalizar, um último exemplo mostrando adição de uma lista à outra lista com append
e extend
.
lista_de_numeros = [1, 2, 3, 4, 5]
lista_de_numeros.append([6, 7, 8, 9])
print(lista_de_numeros)
[1, 2, 3, 4, 5, [6, 7, 8, 9]]
lista_de_numeros = [1, 2, 3, 4, 5]
lista_de_numeros.extend([6, 7, 8, 9])
print(lista_de_numeros)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Conforme exemplificados acima, o append
adiciona a lista [6, 7, 8, 9]
como um objeto único, um elemento a mais na lista inicial, obtendo como resultado uma lista aninhada. O tamanho da lista final é o tamanho da lista inicial + 1 elemento.
No caso do extend
, os elementos da lista [6, 7, 8, 9]
são adicionados um a um à lista inicial. O tamanho da lista final é é o total de elementos da lista inicial + o total de elementos da lista estendida.
insert
#
Tanto o append
quanto o extend
só adicionam/estendem elementos ao final da lista. O insert
tem o mesmo comportamento do append
, sendo possível especificar o índice na qual o elemento será inserido.
Nesta altura do livro, espero que você tenha entendido e se lembre que a indexação em Python começa por 0!
frutas = ["maçã", "banana", "laranja"]
frutas.insert(1, "morango")
print(frutas)
['maçã', 'morango', 'banana', 'laranja']
Remoção de elementos#
Para remoção de elementos, também temos 3 métodos:
remove( )
: Remove a primeira ocorrência de um item da lista.pop( )
: Remove e retorna o item em uma posição específica.clear( )
: Remove todos os itens da lista.
remove
#
O método remove
apaga a primeira ocorrência da esquerda para direita de um item da lista.
frutas = ["maçã", "banana", "laranja", "banana"]
frutas.remove("banana")
print(frutas)
['maçã', 'laranja', 'banana']
Observem que tínhamos 2 ocorrências de banana
na lista inicial, nos índices 1 e 3 da lista. A primeira aplicação de frutas.remove('banana')
removeu apenas banana
do índice 1.
frutas = ["maçã", "banana", "laranja", "banana"]
frutas.remove("fruta inexistente")
print(frutas)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[15], line 2
1 frutas = ["maçã", "banana", "laranja", "banana"]
----> 2 frutas.remove("fruta inexistente")
3 print(frutas)
ValueError: list.remove(x): x not in list
Caso o elemento não seja encontrado, o nosso código vai apresentar o erro com a mensagem ValueError: list.remove(x): x not in list
, informando que o elemento passado não está na lista
pop
#
O método pop
remove e retorna o item em um índice específico.
O pop
atua diferente do remove
. No remove
passamos o elemento em si, e no pop
passamos a posição do elemento que será removido, e não o elemento em si.
frutas = ["maçã", "banana", "laranja"]
frutas.pop(0)
print(frutas)
['banana', 'laranja']
Além disso, há outra diferença. No caso do remove
, não conseguimos salvar o elemento removido em uma variável, pois ele não é retornado. Já no pop
, o elemento removido é retornado, sendo possível salvá-lo em uma variável para uso posterior. Vejamos exemplos:
Quando salvamos o resultado de frutas.remove("banana")
na variável fruta_removida
, ela não recebe nenhum valor, e acaba representanda pelo valor nulo None
em Python.
frutas = ["maçã", "banana", "laranja", "banana"]
fruta_removida = frutas.remove("banana")
print(fruta_removida)
None
Porém, quando salvamos o resultado de frutas.pop(0)
na variável fruta_removida
, ela recebe o valor do elemento removido. Por isso frisei a funcionalidade do pop
como remove e retorna o item pela posição.
frutas = ["maçã", "banana", "laranja", "banana"]
fruta_removida = frutas.pop(0)
print(fruta_removida)
print(frutas)
maçã
['banana', 'laranja', 'banana']
Quando nenhum índice é passado para o pop
, ele remove e retorna o último elemento da lista por padrão.
frutas = ["maçã", "banana", "laranja", "banana"]
fruta_removida = frutas.pop()
print(fruta_removida)
print(frutas)
banana
['maçã', 'banana', 'laranja']
clear
#
O método clear
é simples. Ele limpa toda a lista, removendo todos os elementos. Aqui não há segredos.
frutas = ["maçã", "banana", "laranja", "banana"]
frutas.clear()
print(frutas)
[]
Informações sobre a lista#
Aqui temos 2 métodos:
index()
: Retorna o índice da primeira ocorrência de um item.count()
: Retorna o número de ocorrências de um item na lista.
index
#
O método index
é bem simples e serve para buscar pelo menor índice de um dado elemento, sendo muito útil em localizar a posição de itens em uma lista. No exemplo abaixo, o primeiro índice encontrado para banana
é o índice 1.
frutas = ["maçã", "banana", "laranja", "banana"]
indice = frutas.index("banana")
print("Menor índice encontrado:", indice)
Menor índice encontrado: 1
Caso o elemento não seja encontrado, o erro ValueError
equivalente ao remove
aparecerá.
frutas = ["maçã", "banana", "laranja", "banana"]
indice = frutas.index("fruta inexistente")
print("Menor índice encontrado:", indice)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[22], line 2
1 frutas = ["maçã", "banana", "laranja", "banana"]
----> 2 indice = frutas.index("fruta inexistente")
3 print("Menor índice encontrado:", indice)
ValueError: 'fruta inexistente' is not in list
count
#
O método count
é similar ao que vimos em strings, para contar quantas vezes um dado elemento aparece na lista.
frutas = ["maçã", "banana", "laranja", "banana"]
contador = frutas.count("banana")
print("Quantidade de ocorrências de banana encontrada:", contador)
Quantidade de ocorrências de banana encontrada: 2
Ordenação e reversão#
Temos 2 métodos aqui:
sort()
: Ordena os itens da lista.reverse()
: Inverte a ordem dos itens na lista.
sort
#
O método sort
ordena uma dada lista em ordem crescente ou decrescente. Para definir entre crescente e decrescente é possível usar o parâmetro reverse
, que, por padrão, assume o valor reverse=False
. Em outras palavras, o padrão de ordenação, quando nenhum parâmetro é passado, é crescente.
numeros = [3, 1, 4, 1, 5, 9, 2]
numeros.sort()
print("Ordem crescente:", numeros)
numeros.sort(reverse=True)
print("Ordem decrescente:", numeros)
Ordem crescente: [1, 1, 2, 3, 4, 5, 9]
Ordem decrescente: [9, 5, 4, 3, 2, 1, 1]
Quando os elementos são strings, a ordenação é feita de forma alfabética.
nomes = ["João", "José", "Jonas", "Joaquim", "Caio", "Antônio"]
nomes.sort()
print("Ordem alfabética:", nomes)
nomes.sort(reverse=True)
print("Ordem alfabética reversa:", nomes)
Ordem alfabética: ['Antônio', 'Caio', 'Joaquim', 'Jonas', 'José', 'João']
Ordem alfabética reversa: ['João', 'José', 'Jonas', 'Joaquim', 'Caio', 'Antônio']
Quando os tipos de dados da lista são misturados, não é possível fazer a ordenação.
tipos_misturados = [1, "1", "Henrique", 4.0]
tipos_misturados.sort()
print("Ordem crescente:", tipos_misturados)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[26], line 2
1 tipos_misturados = [1, "1", "Henrique", 4.0]
----> 2 tipos_misturados.sort()
3 print("Ordem crescente:", tipos_misturados)
TypeError: '<' not supported between instances of 'str' and 'int'
reverse
#
O método reverse
inverte uma dada lista ao contrário. É diferente do sort
, que ordena.
tipos_misturados = [1, "1", "Henrique", 4.0]
tipos_misturados.reverse()
print("Lista invertida:", tipos_misturados)
Lista invertida: [4.0, 'Henrique', '1', 1]
Outras operações com listas#
Pertencimento#
É possível verificar se um dado elemento está ou não em uma lista usando os operadores not
e in
nomes = ["João", "José", "Jonas", "Joaquim", "Caio", "Antônio"]
print("João" in nomes)
True
nomes = ["João", "José", "Jonas", "Joaquim", "Caio", "Antônio"]
print("Nome inexistente" not in nomes)
True
Comprimento#
Como já vimos em strings, é possível usar a função len
para mensurar o tamanho de uma lista.
nomes = ["João", "José", "Jonas", "Joaquim", "Caio", "Antônio"]
quantidade_nomes = len(nomes)
print(f"A lista tem {quantidade_nomes} nomes.")
A lista tem 6 nomes.
Lembrete (len é função e não método)
A esta altura do livro você deve estar confortável em saber porque usamos len(nomes)
e não nomes.len()
. O motivo: `len()´ é uma função e não um método de lista, conforme vimos na seção reforço prático - métodos vs funções.
Iterando pela lista#
Podemos já adiantar um tema que vamos detalhar mais em capítulos futuros, o laço for
. Basicamente, e de forma simplificada, podemos iterar pelos elementos de uma lista.
nomes = ["João", "José", "Jonas", "Joaquim", "Caio", "Antônio"]
for nome in nomes:
print(nome)
João
José
Jonas
Joaquim
Caio
Antônio
No exemplo acima, estamos usando uma variável temporária nome
, que recebe cada um dos nomes da lista nomes
. Cada item da lista é impresso na tela.
Nota (identação)
Reparem bem na linha print(nome)
. Há vários espaços em branco à direita dela. Pela primeira vez estamos usando identação no código.
Em Python, a identação são espaços que colocamos no começo das linhas. Ela ajuda o computador a entender que partes do código pertencem juntas.
A linha print(nome)
está indentada, o que significa que ela pertence ao bloco do laço de repetição for
da linha acima. O que está indentado aqui é a ação que queremos realizar para cada nome na lista. Nesse caso, a ação é imprimir o nome na tela.
Vamos detalhar mais a fundo a identação quando começarmos a estudar estruturas de decisão if-else
e laços de repetição for
e while
.
O que você precisa entender por agora é que a identação é obrigatória, caso contrário o código vai gerar um erro. Experimente executar o trecho abaixo e veja você mesmo o erro:
nomes = ["João", "José", "Jonas", "Joaquim", "Caio", "Antônio"]
for nome in nomes:
print(nome)
Substituindo valores#
Como vimos bem lá no começo deste capítulo, listas são objetos mutáveis. Por isso temos vários métodos de inserção e deleção de itens em uma lista. Mas podemos também alterar valores já existentes. Vejamos um exemplo:
nomes = ["João", "José", "Jonas", "Joaquim", "Caio", "Antônio"]
nomes[0] = "Fernando"
print(nomes)
['Fernando', 'José', 'Jonas', 'Joaquim', 'Caio', 'Antônio']
Aqui, a linha nomes[0] = "Fernando"
é responsável por substituir no índice 0 o nome existente João
pelo Fernando
.