Alura > Cursos de Programação > Cursos de Python > Conteúdos de Python > Primeiras aulas do curso Python Collections parte 1: listas e tuplas

Python Collections parte 1: listas e tuplas

Listas e operações - Introdução

Boas-vindas ao curso de introdução as coleções com Python: Python Collections parte 1: Listas e tuplas. Eu sou o Guilherme Silveira, e nesse curso nós vamos abordar um pouco de lista, um pouco de tupla, vamos citar a existência das arrays como tipos dentro do Python e das arrays do numpy. Mas, o nosso foco nesse curso mesmo é trabalhar com listas e tuplas entender quando usar uma, quando utilizar a outra, qual a regra geral positiva que as pessoas utilizam para definir, vou usar essa daqui, vou usar aquela ali para as minhas coleções.

E também como utilizá-las, então precisamos saber também quais são as funções que existem, que recebem iteráveis, que recebem listas e tuplas como parâmetros. Além disso, quais são os métodos, por exemplo, que uma lista apresenta para podermos trabalhar em casos comuns do dia a dia, seja: uma ordenação, inverter uma ordem, enumerar os resultados, utilizar comparações baseadas em funções separadas, ou baseadas em uma ordenação natural que adicionamos ao nossos próprios objetos.

Então tem muita coisa para vermos aqui durante esse curso, então começamos com um exemplo simples de listas baseadas em inteiros e vai até exemplos mais complexos onde usamos diversos decorators, para poder criar critérios de comparação e outras coisas dentro do nosso código.

Os pré-requisitos para esse curso são, já conhecer a linguagem Python, então o primeiro curso de Python e também já conhecer um pouco de orientação a objetos utilizando o Python, que é o primeiro curso de orientação a objetos com o Python, se você já fez o segundo curso de orientação objeto com Python, melhor ainda, porque aqui nós utilizamos alguns exemplos de herança também para mostrar algumas variações que vão ocorrendo a medida que utilizamos listas e polimorfismo.

Então tudo isso vamos ver aqui nesse curso, que é uma introdução as coleções utilizando essas coleções específicas.

Listas e operações - Introdução as coleções e lista

Vamos começar então esse nosso curso de introdução as coleções com Python. Nesse curso, nós vamos utilizar o Google Colab, que é uma versão online da ferramenta Jupyter Notebook, você pode utilizar também a IDE do PyCharm ou outra ferramenta que você goste para executar scripts de Python, ou código em Python, o que você preferir.

Eu vou utilizar o Google Colab porque vai ser super prático para executarmos trechos de código e manter o histórico, o Jupiter Notebook também permite fazer isso, localmente, por exemplo.

Para isso, basta acessar a URL https://colab.research.google.com/notebooks/intro.ipynb#recent=true, se logar com sua conta ou uma conta do Google qualquer e aí você cria um notebook do Python 3, então não precisa instalar o Python 3 na sua máquina se você não quiser nesse instante. Se você estiver em uma máquina do seu tio, da sua tia, de outra pessoa, você consegue entrar para mostrar alguma coisa, não tem problema nenhum.

Entrando no Google Colab, eu vou criar o meu notebook cujo o nome é “Introdução a Collections”, e a ideia de coleções é que tenhamos mais de um elemento. Se é uma coleção, são vários elementos. Que exemplo que eu tenho de vários elementos no dia a dia? Vamos pensar na idade de diversos usuários do meu site, então eu tenho um site, eu armazeno a idade dos usuários e eu tenho várias idades, e eu posso anotar a idade1 = 39, a idade2 = 30 e a idade3 = 27.

Para eu trabalhar com isso, se eu quiser agora imprimir as três idades, eu preciso dar um print(idade1), print(idade2), print(idade3), no Jupiter Notebook ou no Google Colab, etc, você pode apertar o botão de play para rodar, se é local no Jupiter Notebook, ele vai rodar na hora basicamente.

Se é remoto como o Google Colab, ele vai se conectar com o cloud do Google, pegar uma instância do Python para rodar para nós, para conectar com essa máquina, e, então, rodar esse código, isso demora um pouco na primeira vez.

E depois que ele já está rodando com esse tempo de execução, você sai rodando várias vezes, então posso apertar o play de novo e agora vai mais rápido, é só ele enviar, executar e trazer, 39, 30 e 27. Mas, supondo que não queremos trabalhar apenas com 3 valores, e que agora são 4, preciso colocar aqui idade 4 = 18, print(idade4), começa a ficar trabalhoso. Portanto, quando falamos em "coleções" significa que queremos o trabalhar com diversos valores, a partir disso, temos várias situações.

Tem uma situação que eu posso falar que eu quero trabalhar com nome da pessoa e a idade, então Guilherme 37, é um caso, não é esse caso que eu estou mostrando - esse caso do Guilherme 37 veremos mais para frente, não tem problema nenhum - mas eu queria agora trabalhar com diversos valores do mesmo tipo, o último tipo base que seja igual. No meu caso, aqui, são números inteiros.

Então existe maneiras de fazer isso, você que já fez um curso de Python básico aqui com nós na Alura, ou já leu um livro e aprendeu de outra maneira, sabe que no Python existe uma lista, a lista permite adicionar diversos elementos do mesmo tipo ou não, mas no nosso caso costumamos trabalhar com listas de mesmo tipo base, então aqui eu vou colocar os nossos quatro valores, idades = [39, 30, 27 e 18].

Então se eu definir a variável idades como uma lista da maneira apresentada acima, eu posso até verificar, o type.(idades) é uma lista, list, e isso existe na documentação do Python, que podemos acessar pela URL https://docs.python.org/3/tutorial/datastructures.html. Temos na documentação do 3.7 em diante que estamos utilizando, a documentação da lista com diversas coisas que podemos fazer com a lista.

Então o que eu posso fazer com a lista? A lista é uma implementação de uma ideia que costumamos chamar de uma sequência, porque é uma sequência de acesso aleatório. Eu posso falar que eu quero acessar o elemento na segunda, o elemento na quarta posição, costumamos chamar isso de array. No Python existe um tipo chamado array, não é esse tipo, nós vamos ver depois.

Então não podemos confundir,se eu disser “Então funciona como em um array de maneira genérica”, estamos falando da ideia de que existe uma sequência de valores e podemos acessar qualquer um desses valores pela posição (0, 1, 2, 3…). Agora, o tipo lista e o tipo array são coisas diferentes no Python - específico do Python - portanto, no Python, temos a lista, que é o que costumamos trabalhar.

Então se eu tenho uma lista, eu posso falar “Quantos elementos tem nessa lista? Qual é o tamanho, - o length, em inglês, ou o len, abreviado - da lista idades?” Quatro, temos 4 elementos. Por exemplo, o elemento na posição zero, idades[0], isto é, começa na posição 0, deveria ser esse 39, vamos conferir selecionando “Shift + Enter” para rodar, é 39. Se eu quiser imprimir tudo, idades, então [39, 30, 27, 18]. E se eu digito aqui o que eu quero imprimir, o resultado da última linha que eu digito é o que vai ser impresso.

Então se eu digitar aqui idades[1], idades[2], idades[3], ele só vai imprimir o meu resultado da última linha que vai ser o 18. Se eu quisesse imprimir tudo, então teria que escrever “print” em todos eles.

print(idades[1])
print(idades[2])
print(idades[3])

Apertando “Shift + Enter”, terei os últimos valores: 30, 27 e 18.

São coisas básicas que aprendemos quando trabalhamos com uma lista, mas uma sacada importante da lista é que cada linguagem tem uma variação de implementação, a lista padrão que utilizamos do Python pode ter seus valores alterados, então, podemos pegar essa nossa lista e adicionar valores nela, posso adicionar ao final um append - lembra do apêndice de um livro? No final de um livro? - que coloca no final o valor 15, então agora eu devo ter: 39, 30, 27, 18, 15.

idades.append(15)
idades
[39,30,27,18,15]

Vamos conferir o idades? O idades está lá com o valor 15, então se eu acessar a posição 4 tem que retornar o valor 15.

idades[4]
15

É possível que vc me pergunte “Guilherme e se você tentar acessar agora a posição 5, que não existe? idades[5]. Como 5 não existe, um IndexError é apresentado, ou seja, a posição está fora do espaço que podemos buscar, que é só do 0 até o 4. São cinco elementos, do 0 até o 4. Podemos acessar aleatoriamente, adicionar no final, imprimir ela inteira, mostrar o tamanho, passar por todos elementos, para cada idade dentro de idades, ela é impressa.

for idade in idades: 
  print(idade)

Então vou apertar “Shift + Enter”, podemos passar por todos elementos e podemos remover um elemento. Vamos, nas idades,remover o 30? idades.remove(30), vamos ver como ficou?

idades.remove(30)
idades
[39,27,18,15]

Não tem mais o 30. Podemos fazer outras coisas aqui, podemos tentar remover de novo o 30, idades.remove(30), que não existe, o que o remove faz? O remove diz “o 30 não está na lista”,ValueError: list.remove(x): not in list. Dá erro.

E se eu tivesse duas vezes o mesmo elemento, então idades.append(15), então vamos ter duas vezes o elemento 15, vamos conferir com idades e mandamos remover o elemento 15, idades.remove(15). qual é o resultado? Ele remove somente uma única vez, remove a primeira aparição do elemento. Para mostrar que é a primeira aparição, temos duas maneiras. Podemos provar adicionando aqui um elemento, eu estou tentando mostrar que é isso que acontece, vou adicionar um 27, remover um 27 e mostrar o resultado.

idades.append(27)
idades.remove(27)
idades
[39,18,15,27]

Então o 27 vai sair daqui e vai aparecer no final, porque eu adicionei no final, removi a primeira aparição e mostrei o resultado para. Temos que nos acostumar a olhar a documentação para ver como os métodos funcionam. Se você olhar na documentação, você vai ver que o append adiciona no fim da lista.

O remove(x), ele remove a primeira vez que o elemento aparece, no caso de aparecerem dois iguais, o que está na lista e o que você passou, e joga um erro se não tem esse valor. Você pode dizer: “Guilherme, agora eu quero remover tudo da lista”, então vamos remover tudo da lista, então, "idades.remove(39), idades.remove(18)..." Será que é mesmo assim?.

Se eu quero remover tudo da lista o que eu faço? Primeiro pensamos “Isso deve ser uma coisa muito comum, que todo mundo que usa biblioteca padrão do Python - que utiliza uma lista - acaba precisando um dia na vida”, então vamos olhar na própria documentação do Python, procuramos e encontramos, clear(), remove todos os elementos.

Entendeu porque é importante nos acostumarmos a procurar em documentação? Caso contrário, eu faria algo manual que teria mais trabalho além de correr o risco de colocar um bug no meu código, sendo que já existe algo padrão para nós. Não tenha medo de enfrentar a documentação e procurar, documentação parece ser chata de ler, ela é chata de ler, mas se você ler à medida que você precisa de alguma coisa, você começa a adicionar novo conhecimento e tampar buraco de como as coisas funcionam.

Então, vimos alguns exemplos de trabalho de manipulação de uma lista, vamos ver outros exemplos daqui a pouco, antes de passarmos para exemplos bem mais complexos.

Listas e operações - Mais operações em listas e list comprehension

Aprendemos com alguns exemplos a trabalhar com uma lista, queria mostrar agora mais exemplos - ainda básicos - de perguntas que vamos fazer para essa lista. Por exemplo, falamos que quando vamos remover uma coisa, dependendo de como acessamos, teremos um ValueError, porque esse elemento não está dentro da lista. O remove, por padrão, vai dar um ValueError se o elemento não está lá.

Então como eu verifico se o elemento está lá antes de removê-lo? Um exemplo, se quisermos simplesmente saber se a idade 28 está dentro de idades, é só eu fazer essa pergunta: 28 in idade. Falso, não está. E 15 está dentro de idades? 15 in idades. Sim, 15 está dentro de idades, então o que eu poderia fazer no caso do remove, ou em outra situação que você gostaria de verificar se um elemento está dentro de uma lista, é fazer um if, é o mais comum.

Se o 15 está dentro de idades, idades.remove(15), por exemplo.

if 15 in idades:
  idades.remove(15)

Podemos imprimir uma mensagem ou verificar uma coisa, depende do que você quer fazer com essa condição, claro. Eu vou dar esse exemplo que vai remover o 15, se ele estiver lá dentro. Como ele está, vamos ver que agora, depois de removido, ele não está mais.

Então antes ele estava e não está mais, [39, 18, 27]. Agora, se eu fizer o mesmo com 28, if 28 in idades, seguido de idades.remove(28), vai continuar do mesmo tamanho, porque o 28 não está em idades. Então é super importante lembrarmos do in, usado bastante para quando queremos filtrar alguma coisa.

E agora que eu falei do in para filtrar, se eu quiser adicionar elementos? “Guilherme, você já falou de adicionar elementos, utilizamos o append”. Mas o append adiciona um elemento no final, então o idades.append(19) vai adicionar o 19 no final, e se eu quisesse adicionar em outra posição? Lembra da importância da documentação? Vamos para a documentação, porque essa é uma pergunta típica, super comum. Por um acaso, a informação está bem na primeira linha, “list.insert(i,x)”, isto é, precisamos inserir um item, que é o item x, na posição desejada.

Ele explica que a posição "0" é o começo da lista, então ele vem antes de todo mundo. Se eu quiser adicionar no começo, eu posso fazer idades.insert(0, 20),isto é, na posição "0" o elemento 20. vamos ver? O 20 precisa estar bem no começo e o resto ser deslocado para direita. Então, [20, 39, 18, 27, 19], demonstrando a importânciao do insert para colocar um número em um ponto específico.

Outro caso muito comum ao incluir elementos, é quando temos vários elementos para incluir. Imagine que eu tenho essa minha lista de idades, que são os três valores: “[20, 39, 18]”.

Agora eu quero incluir ao final o 27 e o 19, o append não vai receber dois argumentos, ele só recebe um. Podemos até tentar coloca-los dentro de uma lista idades.append([27, 19]), ou seja, mandamos adicionar esses dois elementos da lista. Ele funciona, mas não necessariamente como queríamos, a nossa lista idadesfica com vários elementos e com mais uma lista de dois elementos, [20, 39, 18, [27, 19]]

Vamos agora fazer:

for elemento in idades: 
  print("Recebi o elemento", elemento)

Vamos ver cada um dos elementos que temos dentro da nossa lista separados. Temos o 20, o 39, o 18 e o [27, 19], quer dizer, um elemento que é uma lista dentro de outra lista.

Recebi o elemento 20 
Recebi o elemento 39
Recebi o elemento 18
Recebi o elemento [27, 19]

Ficou estranho, como eu disse antes, o uso padrão da lista é que todos elementos vão ter algo de "tipo" em comum, uma tipagem em comum para trabalharmos com for, filtragem, e outros. Um inteiro e uma lista, não costuma ser bem isso.

Não era o que queríamos. O que eu queria era ter 5 elementos: 20, 39, 18, 27 e 19. Eu queria ter pego a lista [27, 19] e colocado elemento a elemento dentro da outra lista original. Então o que eu queria fazer não era um append, eu queria estender essa lista com os elementos da segunda lista, então o método se chama extend().

Se você não sabe o método e pensa “Isso deve ser muito comum”, basta procurar na documentação. E quando você procurar na documentação, vai achar o extend(), que estende a lista adicionando todos os itens desse iterável, numa lista é iterável é passar por todos elementos, então é isso que vamos fazer, vamos estender.

Vamos ver o resultado?

idades = [20, 39, 18]
idades.extend([27, 19])
idades

[20, 39, 18, 27, 19

Agora sim, o resultado são 5 elementos: 20, 39, 18, 27 e 19. Reparem a importância de procurarmos a documentação, de entendermos as funcionalidades que existem dentro dos nossos objetos, ainda mais em uma biblioteca padrão do Python, com muita coisa que é comum para todo mundo, literalmente o mundo inteiro.

Mas, mesmo com bibliotecas que não vem no padrão do Python, que são módulos que você baixa, é bem comum já vai ter coisas prontas, e é só pegar e utilizar. Não tenha medo de explorar os métodos de algum objeto que você trabalha.

Por fim, eu queria mostrar que, além desse for que eu fiz, for elemento in idades, existem outros tipos de for que podemos fazer. Um forcomum é para quando queremos passar por todas as idades e saber qual é o valor delas no ano que vem. Então quer dizer, eu quero trabalhar com esses valores de alguma maneira, com todos os valores. Para isso, podemos fazer o for idade in idades: e eu quero imprimir agora, por exemplo, a idade + 1.

Então, teremos: 21, 40, 19, 28 e 20.

for idade in idades:
  print(idade + 1)

21
40
19
28
20

Funciona, mas o que eu queria era transformar em outro array. Queria um array idades_no_ano_que_vem. A maneira mais antiga, tradicional, de fazer isso é criarmos esse array,idades_no_ano_que_vem = [], que é uma lista vazia.

Agora fazemos o nosso for, e para cada um dos elementos, pegamos o idade + 1 e vamos adicionar esse valor no idades_no_ano_que_vem, para que ele appenda essa valor.

idades_no_ano_que_vem = []
for idade in idades:
  idades_no_ano_que_vem.append(idade+1)

Então, estamos pegando cada um dos valores da nossa lista, adicionando 1 e colocando dentro dessa outra lista. Vamos ver como ficou? Escreveremos idades_no_que_vem, selecionaremos “Shift + Enter” e agora temos um array que é [21, 40, 19, 28, 20]. Transformarmos aquele nosso array em um outro array. Estou usando o termo array no sentido genérico, porque é sempre como se pegássemos uma sequência de elementos iteráveis, podemos iterar como no for.

Então, pegamos a sequência e queremos aplicar alguma operação nela. Por exemplo, a operação que eu queria aplicar no nosso caso é "somar 1", isso é tão comum que existe uma outra sintaxe menor que é, para cada idade dentro de idades, antes do for vamos falar "soma 1", isto é (idade+1).Então "soma 1" para cada idade dentro de idades: (idade+1) for idade in idades. A sintaxe é quase essa, faltou só um colchete, porque queremos transformar isso em uma lista, portanto: [(idade+1) for idade in idades].

Então eu quero criar uma lista, onde vou passar para cada um dos elementos idade, dentro do iterável idades - por isso que estamos usando o termo array várias vezes, por causa do conceito de iteração da minha sequência - e vou "somar + 1" para cada um deles, vamos dar “Shift + Enter” e teremos: 21, 40, 19, 28, 20. Então, passamos pelos elementos, e, para todos elementos, aplicamos alguma coisa, poderia ser qualquer coisa.

E eu posso atribuir isso no idades_no_ano_que_vem, e posso só imprimir essa variável para ter certeza. Se eu quisesse, poderia fazer dessa outra maneira.

idades_no_ano_que_vem = [(idade+1) for idade in idades]
idades_no_ano_que_vem

Quando estamos trabalhando com listas dessa maneira, iterando e criando listas novas, podemos também fazer filtragens. Por exemplo, se eu quero somente as idades maiores que 21 anos, então, não quero 21, 20 ou 19, quero só o 28 e o 40, só quero estritamente maior do que 21.

Então o que eu quero fazer é o mesmo for, for idade in idades, mas eu quero filtr, if idade > 21. É possível escolher tudo isso em uma linha só, então vou colocar o colchete de novo, lembrando que, eu preciso falar o que é a operação que eu quero, que, no caso, não é idade + 1, só quero a idade.

[(idade) for idade in idades if idade > 21]

Então, para todas as idades, o que for maior que 21 eu mantenho, se não for, jogo fora.

Vamos ver o resultado? A lista original era: 20 (joga fora); 39 (fica); 18 (joga fora); 27 (fica); 19 (joga fora). Então, o if permite que filtremos. Um detalhe importante é que o parênteses é opcional, podemos tirar, [idade for idade in idades if idade > 21], ele é utilizado apenas em alguns casos, porque a legibilidade fica melhor.

E, é claro, quanto mais complexa a sua operação, mais difícil vai ficar de entender, então, se fosse:

[idade + 1 for idade in idades if idade > 21]

Funciona, mas temos várias maneiras de fazer, porque, imagine que isso poderia ser muito complexo.

Uma possibilidade é definir uma função, def proximo_ano(idade):, e retornar return idade + 1. É uma outra abordagem. Seguindo, ao invés de fazer idade + 1, poderíamos ter proximo_ano(idade), isto é, aplico o próximo ano para a idade, é uma outra variação.

def proximo ano(idade):
  return idade+1

[proximo_ano(idade) for idade in idades if idade > 21]

Funciona sem problema algum. Claro, quando é só idade + 1, ainda não temos um super ganho, mas se isso fosse um código super complexo de três linhas, ou super longo, não perderíamos a legibilidade.

Então repare que, dessa maneira, com esses colchetes que utilizamos aqui e criamos lista novas que chamamos de # list comprehension, conseguimos iterar por diversos elementos de um iterável, aplicar filtros e transformações, então já conseguimos fazer muita coisa legal com listas.

Sobre o curso Python Collections parte 1: listas e tuplas

O curso Python Collections parte 1: listas e tuplas possui 138 minutos de vídeos, em um total de 49 atividades. Gostou? Conheça nossos outros cursos de Python em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Python acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas