Uma list comprehension cria uma lista nova a partir de outra coleção, em uma linha. A estrutura é sempre [ expressão for item in coleção if condição ] — onde a expressão decide o que entra, e o if (opcional) filtra quais itens passam.
# for + append (longo)
caes = []
for pet in pets:
if pet.especie == "Cão":
caes.append(pet)
# comprehension equivalente (1 linha)
caes = [pet for pet in pets if pet.especie == "Cão"] Leia a comprehension como uma frase: "o pet, pra cada pet em pets, se o pet for Cão".
Na lista, pra achar um objeto você percorre tudo com for+if. No dicionário, cada objeto tem uma chave (id, código, matrícula) e a busca é direta: a chave leva instantaneamente ao objeto. Use dict quando há um identificador natural pelo qual você vai procurar.
A chave do dict é o endereço do objeto: você vai direto, sem procurar na lista inteira.
Pra descobrir se um elemento já está dentro dele, o set usa o hash do elemento. Por isso, pra guardar objetos numa coleção sem repetição, a classe precisa definir __eq__ (quando dois objetos são iguais) e __hash__ (o número que os identifica) — exatamente os métodos da aula 11. Sem eles, cada objeto é tratado como único e o set não remove repetidos.
class Tag:
def __init__(self, nome):
self.nome = nome
def __eq__(self, outra):
return self.nome == outra.nome
def __hash__(self):
return hash(self.nome)
tags = {Tag("vacinado"), Tag("castrado"), Tag("vacinado")}
print(len(tags)) # 2 lambda é uma função anônima de uma linha. lambda obj: obj.atributo significa "dado um obj, devolva esse atributo". No sorted, o key= recebe um lambda que diz POR QUAL atributo ordenar — é o critério de ordenação que o Python sozinho não adivinha.
# por idade, crescente
por_idade = sorted(pets, key=lambda pet: pet.idade)
# do mais velho pro mais novo
mais_velhos = sorted(pets, key=lambda pet: pet.idade, reverse=True)
# por nome, em ordem alfabética
por_nome = sorted(pets, key=lambda pet: pet.nome) Na aula passada salvamos um objeto por vez. Hoje aprendemos a manipular coleções inteiras: list, dict, set e tuple — e como as suas classes conversam com for, in, comprehension e sorted.
roteiro da aula
Guardar vários objetos numa lista só e processar todos com um for.
O dicionário como repositório: a chave aponta direto pro objeto, sem percorrer tudo.
Buscar um objeto, filtrar por critério e iterar — incluindo o set, que elimina repetição.
List comprehension pra condensar, e sorted(key=lambda) pra ordenar objetos.
ponte com a aula passada
o problema
Quando cada objeto vive numa variável separada, qualquer processamento vira repetição manual.
class Pet:
def __init__(self, nome, especie, idade):
self.nome = nome
self.especie = especie
self.idade = idade
pet1 = Pet("Rex", "Cão", 4)
pet2 = Pet("Mimi", "Gato", 2)
pet3 = Pet("Thor", "Cão", 7)
pet4 = Pet("Bidu", "Cão", 1)
# Sem coleção, sobra trabalho manual e repetição:
print(pet1.nome, pet1.especie, pet1.idade) # Rex Cão 4
print(pet2.nome, pet2.especie, pet2.idade) # Mimi Gato 2
print(pet3.nome, pet3.especie, pet3.idade) # Thor Cão 7
print(pet4.nome, pet4.especie, pet4.idade) # Bidu Cão 1
# E se fossem 200 pets? Repetir print 200 vezes é inviável. listas
Uma lista guarda vários objetos numa variável só. Um for processa todos — não importa se são 3 ou 300.
class Pet:
def __init__(self, nome, especie, idade):
self.nome = nome
self.especie = especie
self.idade = idade
def __str__(self):
return f"{self.nome} ({self.especie}, {self.idade} anos)"
# uma lista guarda vários objetos numa variável só
pets = [Pet("Rex", "Cão", 4), Pet("Mimi", "Gato", 2), Pet("Thor", "Cão", 7)]
print(len(pets)) # 3
for pet in pets:
print(pet)
# Rex (Cão, 4 anos)
# Mimi (Gato, 2 anos)
# Thor (Cão, 7 anos) panorama
| item | detalhe |
|---|---|
| list — [ ] | Ordenada e mutável. Aceita repetidos e tem índice. É a coleção do dia a dia. |
| tuple — ( ) | Ordenada, mas IMUTÁVEL: depois de criada não muda. Boa pra dados fixos (ex.: coordenadas). |
| dict — { chave: valor } | Mapeia uma chave a um valor. Acesso direto pela chave, sem percorrer tudo. O repositório. |
| set — set( ) | Sem ordem e SEM repetição. Guarda elementos distintos. Ótimo pra eliminar duplicatas. |
listas
append, len, in, índice, fatia e for — o ferramental que você usa o tempo todo.
pets = ["Rex", "Mimi", "Thor"]
pets.append("Bidu") # adiciona no fim
print(pets) # ['Rex', 'Mimi', 'Thor', 'Bidu']
print(len(pets)) # 4
print("Mimi" in pets) # True
print(pets[0]) # Rex (índice começa em 0)
print(pets[-1]) # Bidu (índice negativo: de trás pra frente)
print(pets[1:3]) # ['Mimi', 'Thor'] (fatia: do 1 ao 2)
for nome in pets:
print(nome) # Rex / Mimi / Thor / Bidu (um por linha) buscar e filtrar
O padrão de busca: percorre com for, compara um atributo, devolve o objeto ao achar — ou None no fim.
class Pet:
def __init__(self, nome, especie, idade):
self.nome = nome
self.especie = especie
self.idade = idade
def __str__(self):
return f"{self.nome} ({self.especie}, {self.idade} anos)"
pets = [Pet("Rex", "Cão", 4), Pet("Mimi", "Gato", 2), Pet("Thor", "Cão", 7)]
def buscar_por_nome(lista, alvo):
for pet in lista:
if pet.nome == alvo:
return pet # achou: devolve o objeto e para
return None # percorreu tudo e não achou
print(buscar_por_nome(pets, "Mimi")) # Mimi (Gato, 2 anos)
print(buscar_por_nome(pets, "Bidu")) # None buscar e filtrar
Montar uma lista nova só com quem passa num critério: lista vazia, for, if, append. É a base do que vem a seguir.
class Pet:
def __init__(self, nome, especie, idade):
self.nome = nome
self.especie = especie
self.idade = idade
def __str__(self):
return f"{self.nome} ({self.especie}, {self.idade} anos)"
pets = [Pet("Rex", "Cão", 4), Pet("Mimi", "Gato", 2), Pet("Thor", "Cão", 7)]
# o jeito tradicional: lista vazia + for + if + append
caes = []
for pet in pets:
if pet.especie == "Cão":
caes.append(pet)
for cao in caes:
print(cao)
# Rex (Cão, 4 anos)
# Thor (Cão, 7 anos) comprehension
A comprehension faz o mesmo que for + append, em uma linha. Compare lado a lado — o resultado é idêntico.
class Pet:
def __init__(self, nome, especie, idade):
self.nome = nome
self.especie = especie
self.idade = idade
def __str__(self):
return f"{self.nome} ({self.especie}, {self.idade} anos)"
pets = [Pet("Rex", "Cão", 4), Pet("Mimi", "Gato", 2), Pet("Thor", "Cão", 7)]
# forma longa: for + append (3 linhas)
caes = []
for pet in pets:
if pet.especie == "Cão":
caes.append(pet)
# forma condensada: list comprehension (1 linha) — mesmo resultado
caes = [pet for pet in pets if pet.especie == "Cão"]
for cao in caes:
print(cao)
# Rex (Cão, 4 anos)
# Thor (Cão, 7 anos) comprehension
Dois usos: TRANSFORMAR (mudar cada item) e FILTRAR (escolher itens). A anatomia é sempre a mesma.
class Pet:
def __init__(self, nome, especie, idade):
self.nome = nome
self.especie = especie
self.idade = idade
def __str__(self):
return f"{self.nome} ({self.especie}, {self.idade} anos)"
pets = [Pet("Rex", "Cão", 4), Pet("Mimi", "Gato", 2), Pet("Thor", "Cão", 7)]
# TRANSFORMAR: uma lista só com os nomes
nomes = [pet.nome for pet in pets]
print(nomes) # ['Rex', 'Mimi', 'Thor']
# FILTRAR: só os pets com 5 anos ou mais
idosos = [pet for pet in pets if pet.idade >= 5]
print([p.nome for p in idosos]) # ['Thor']
# anatomia: [ expressão for item in coleção if condição ]
# pet.nome for pet in pets (sem if = todos) comprehension
Mesmo resultado. À esquerda, quatro linhas e uma variável de acumulação. À direita, uma linha que se lê como uma frase.
caes = []
for pet in pets:
if pet.especie == "Cão":
caes.append(pet)
# 4 linhas + uma lista vazia
# pra inicializar. caes = [pet for pet in pets
if pet.especie == "Cão"]
# 1 instrução. O Python já
# entende: "a lista dos
# pets que são Cão". dict
Na lista você procura percorrendo tudo. No dict, a chave aponta DIRETO pro objeto — busca instantânea.
class Pet:
def __init__(self, codigo, nome, especie):
self.codigo = codigo
self.nome = nome
self.especie = especie
def __str__(self):
return f"[{self.codigo}] {self.nome} ({self.especie})"
# dicionário = repositório: a chave (código) aponta direto pro objeto
repositorio = {
"P01": Pet("P01", "Rex", "Cão"),
"P02": Pet("P02", "Mimi", "Gato"),
}
print(repositorio["P01"]) # [P01] Rex (Cão)
print(repositorio["P02"]) # [P02] Mimi (Gato)
# sem percorrer a lista inteira: a chave leva direto ao objeto. dict
Inserir, buscar, testar, remover e percorrer — o ferramental do dict.
repositorio = {"P01": "Rex", "P02": "Mimi"}
repositorio["P03"] = "Thor" # inserir/atualizar pela chave
print(repositorio.get("P01")) # Rex (busca segura)
print(repositorio.get("P99")) # None (chave ausente: devolve None)
print("P02" in repositorio) # True (testa se a chave existe)
del repositorio["P02"] # remover pela chave
print(list(repositorio.keys())) # ['P01', 'P03']
print(list(repositorio.values())) # ['Rex', 'Thor']
print(list(repositorio.items())) # [('P01', 'Rex'), ('P03', 'Thor')] dict
Com .items() o for recebe a chave E o objeto a cada volta — desempacotados em duas variáveis.
class Pet:
def __init__(self, codigo, nome, especie):
self.codigo = codigo
self.nome = nome
self.especie = especie
def __str__(self):
return f"[{self.codigo}] {self.nome} ({self.especie})"
repositorio = {
"P01": Pet("P01", "Rex", "Cão"),
"P02": Pet("P02", "Mimi", "Gato"),
}
# .items() entrega a chave E o valor a cada volta
for codigo, pet in repositorio.items():
print(f"{codigo} -> {pet}")
# P01 -> [P01] Rex (Cão)
# P02 -> [P02] Mimi (Gato) dict · a armadilha
Buscar uma chave que não existe: o colchete ESTOURA; o .get() devolve None. Escolha o jeito seguro.
repositorio = {"P01": "Rex"}
print(repositorio["P99"])
# KeyError: 'P99'
# o programa para com erro se a
# chave não existir. repositorio = {"P01": "Rex"}
print(repositorio.get("P99"))
# None
print(repositorio.get("P99", "vazio"))
# vazio (padrão que você escolhe) set
O set guarda elementos DISTINTOS. Jogue uma coleção com repetidos dentro dele e as duplicatas somem.
class Pet:
def __init__(self, nome, especie):
self.nome = nome
self.especie = especie
pets = [Pet("Rex", "Cão"), Pet("Mimi", "Gato"), Pet("Thor", "Cão"), Pet("Lulu", "Gato")]
# set() elimina repetições automaticamente
especies = set(pet.especie for pet in pets)
print(especies) # {'Cão', 'Gato'} (a ordem pode variar — set não tem ordem)
print(len(especies)) # 2 (4 pets, mas só 2 espécies distintas) set
Pro set decidir se dois objetos são "o mesmo", a classe precisa de __eq__ e __hash__ — exatamente os métodos da aula 11.
class Tag:
def __init__(self, nome):
self.nome = nome
def __eq__(self, outra): # quando duas Tags são "iguais"? (aula 11)
return self.nome == outra.nome
def __hash__(self): # o set usa o hash pra detectar repetição
return hash(self.nome)
def __str__(self):
return self.nome
# duas tags "vacinado" são consideradas a mesma → o set guarda só uma
tags = {Tag("vacinado"), Tag("castrado"), Tag("vacinado")}
print(len(tags)) # 2 set
Sets falam a linguagem da matemática: união, interseção e diferença com um operador cada.
caes = {"Rex", "Thor", "Bidu"}
vacinados = {"Rex", "Mimi"}
print(caes | vacinados) # união: todos, sem repetir
# {'Rex', 'Thor', 'Bidu', 'Mimi'} (a ordem pode variar)
print(caes & vacinados) # interseção: só quem está nos dois
# {'Rex'}
print(caes - vacinados) # diferença: cães que NÃO estão em vacinados
# {'Thor', 'Bidu'} (a ordem pode variar) ordenar
Tentar ordenar uma lista de objetos direto não funciona: o Python não sabe POR QUAL atributo ordenar.
class Pet:
def __init__(self, nome, idade):
self.nome = nome
self.idade = idade
pets = [Pet("Thor", 7), Pet("Rex", 4), Pet("Mimi", 2)]
# tentar ordenar objetos direto NÃO funciona: o Python não sabe o critério
pets.sort()
# TypeError: '<' not supported between instances of 'Pet' and 'Pet' ordenar
O key= diz qual atributo usar como critério. lambda é uma mini-função de uma linha que extrai esse atributo.
class Pet:
def __init__(self, nome, idade):
self.nome = nome
self.idade = idade
def __str__(self):
return f"{self.nome} ({self.idade} anos)"
pets = [Pet("Thor", 7), Pet("Rex", 4), Pet("Mimi", 2)]
# lambda = função anônima de 1 linha. lambda pet: pet.idade
# significa "dado um pet, devolva pet.idade" — é o CRITÉRIO de ordenação.
por_idade = sorted(pets, key=lambda pet: pet.idade)
for pet in por_idade:
print(pet)
# Mimi (2 anos)
# Rex (4 anos)
# Thor (7 anos)
# reverse=True ordena do maior pro menor
mais_velhos = sorted(pets, key=lambda pet: pet.idade, reverse=True)
print([p.nome for p in mais_velhos]) # ['Thor', 'Rex', 'Mimi'] ordenar · a armadilha
Dois jeitos de ordenar, com comportamentos bem diferentes. Confundir os dois gera a pegadinha clássica do None.
numeros = [3, 1, 2]
novos = sorted(numeros)
print(novos) # [1, 2, 3]
print(numeros) # [3, 1, 2]
# a original fica INTACTA;
# o resultado é uma lista nova. numeros = [3, 1, 2]
resultado = numeros.sort()
print(numeros) # [1, 2, 3]
print(resultado) # None
# .sort() ordena a própria lista
# e devolve None — NÃO faça
# x = lista.sort()! quando usar cada uma
| item | detalhe |
|---|---|
| list — quando a ORDEM importa | Vários objetos numa sequência; aceita repetidos; percorre com for; busca por nome com for+if. |
| dict — quando há uma CHAVE natural | Cada objeto tem um id/código/matrícula; busca direta com .get(chave); percorre com .items(). |
| set — quando quer DISTINTOS | Eliminar repetição (espécies, gêneros, tags); operações | & -; exige __eq__/__hash__ pra objetos. |
| tuple — quando os dados são FIXOS | Imutável: coordenadas, RGB, registros que não mudam. Garante que ninguém altere por engano. |
ao vivo · vamos construir juntos
Vou montar esse na frente de vocês, do zero. Objetivo: uma lista de Produto que a gente sabe buscar pelo nome, filtrar por preço, ordenar com sorted(key=lambda) e listar as categorias distintas com set. Acompanhem o raciocínio passo a passo.
Com nome, preco e categoria, e um __str__ formatado (ex.: Mouse — R$ 80.00 (Informática)). Crie uma lista com 5 produtos.
Uma função buscar(lista, nome) que devolve o objeto ou None; e uma comprehension que filtra só os produtos até R$ 200.
sorted(produtos, key=lambda p: p.preco) pra listar do mais barato pro mais caro — sem alterar a lista original.
Um set(p.categoria for p in produtos) pra descobrir quantas categorias diferentes existem no catálogo.
resolução · passo 1
Começamos pela classe: três atributos e um __str__ que já entrega o produto formatado. E a lista com cinco itens.
:.2f formata o preço com 2 casas decimais.__str__ (aula 03) deixa cada produto pronto pro print() — a regra de exibição mora na classe.class Produto:
def __init__(self, nome, preco, categoria):
self.nome = nome
self.preco = preco
self.categoria = categoria
def __str__(self):
return f"{self.nome} — R$ {self.preco:.2f} ({self.categoria})"
produtos = [
Produto("Notebook", 3500.0, "Informática"),
Produto("Mouse", 80.0, "Informática"),
Produto("Cadeira", 750.0, "Móveis"),
Produto("Mesa", 1200.0, "Móveis"),
Produto("Teclado", 150.0, "Informática"),
]
for produto in produtos:
print(produto)
# Notebook — R$ 3500.00 (Informática)
# Mouse — R$ 80.00 (Informática)
# Cadeira — R$ 750.00 (Móveis)
# Mesa — R$ 1200.00 (Móveis)
# Teclado — R$ 150.00 (Informática) resolução · passo 2
Uma função de busca que devolve o objeto ou None, e uma comprehension que filtra por preço.
buscar() percorre com for, compara o atributo e devolve o objeto ao achar — ou None no fim.[p for p in produtos if p.preco <= 200] lê-se: "os produtos cujo preço é até 200".# BUSCAR um produto pelo nome (devolve o objeto ou None)
def buscar(lista, nome):
for produto in lista:
if produto.nome == nome:
return produto
return None
print(buscar(produtos, "Mouse")) # Mouse — R$ 80.00 (Informática)
print(buscar(produtos, "Geladeira")) # None
# FILTRAR com comprehension: só os produtos até R$ 200
baratos = [p for p in produtos if p.preco <= 200]
print([p.nome for p in baratos]) # ['Mouse', 'Teclado'] resolução · passos 3 e 4 · saída esperada
Fechamos com sorted(key=lambda) pra ordenar por preço e um set pra contar as categorias distintas.
key=lambda p: p.preco diz "ordene comparando o preço de cada produto".set revela só 2 categorias: Informática e Móveis.# ORDENAR por preço (do mais barato pro mais caro)
por_preco = sorted(produtos, key=lambda p: p.preco)
for produto in por_preco:
print(produto)
# Mouse — R$ 80.00 (Informática)
# Teclado — R$ 150.00 (Informática)
# Cadeira — R$ 750.00 (Móveis)
# Mesa — R$ 1200.00 (Móveis)
# Notebook — R$ 3500.00 (Informática)
# categorias distintas, sem repetição, usando set
categorias = set(p.categoria for p in produtos)
print(len(categorias)) # 2 recapitulando
| item | detalhe |
|---|---|
| list / tuple / dict / set | Ordenada mutável [ ] / ordenada imutável ( ) / chave→valor { } / distintos sem ordem set( ). |
| list comprehension | [expressão for item in coleção if condição] — cria uma lista nova transformando/filtrando. |
| lambda | Função anônima de uma linha: lambda obj: obj.atributo. Usada como critério no key=. |
| sorted(lista, key=...) | Devolve uma lista NOVA ordenada pelo critério do key=; aceita reverse=True. |
| lista.sort() | Ordena a própria lista (in-place) e devolve None. Não faça x = lista.sort(). |
| dict.get(chave) | Busca segura: devolve None (ou um padrão) se a chave não existir. Evita o KeyError do [ ]. |
exercícios · visão geral
Cinco exercícios em três níveis. Começamos juntos agora, em sala — quem não fechar todos, termina em casa. Mire pelo menos um de cada nível antes da próxima aula.
2 exercícios — Catálogo de filmes e Agenda telefônica. Foco: lista de objetos + comprehension, e dict com .get() e .items().
2 exercícios — Repositório de Alunos e Ranking de jogadores. Foco: dict-repositório + comprehension, e sorted(key=lambda).
1 exercício — Catálogo de músicas com tags únicas. Foco: juntar lista + comprehension + set (com __hash__/__eq__) + ordenação.
exercícios · nível fácil
Crie a classe Filme com titulo, genero e ano, e um __str__ que mostre algo como Matrix (Ação, 1999). Monte uma lista com 5 ou mais filmes e: (a) imprima todos com um for; (b) use uma comprehension pra criar uma lista só com os títulos; (c) use uma comprehension com if pra pegar só os filmes de 2000 em diante. Foco: lista de objetos + comprehension pra transformar e filtrar.
Monte um dicionário agenda que mapeia nome → telefone, com 4 contatos. Depois: (a) imprima o telefone de um contato com agenda[nome]; (b) busque um nome que NÃO está na agenda usando .get() e mostre que ele devolve None (sem estourar); (c) percorra a agenda inteira com for nome, telefone in agenda.items() imprimindo cada par. Foco: dict como repositório, .get() vs [ ], e .items().
exercícios · nível médio
Classe Aluno com matricula, nome e media (float) e um __str__ formatado. Classe Repositorio que guarda os alunos num dict por matrícula, com: adicionar(aluno) (insere usando a matrícula como chave); buscar(matricula) que devolve o aluno ou None (use .get()); e aprovados() que devolve, via comprehension sobre .values(), a lista de alunos com média ≥ 6.0. Teste com 5 alunos e imprima os aprovados. Foco: dict-repositório + comprehension sobre os valores do dict.
Classe Jogador com nome e pontos (int) e um __str__. Monte uma lista com 6 jogadores e, usando sorted com key=lambda: (a) ordene do maior pro menor em pontos (reverse=True); (b) ordene em ordem alfabética por nome. Ao final, imprima a lista original e mostre que o sorted não a alterou. Foco: sorted(key=lambda), reverse, e a diferença entre sorted() e .sort().
exercícios · nível desafio
Classe Musica com titulo, artista e genero, um __str__ e os métodos __eq__/__hash__ que considerem duas músicas iguais quando têm o mesmo (titulo, artista) — assim o set elimina repetidas. Classe Catalogo que guarda uma lista de músicas, com: adicionar(musica); por_genero(g) que devolve, via comprehension, só as músicas de um gênero; generos_disponiveis() que devolve um set com os gêneros distintos; e top_artistas() que devolve um set com os artistas distintos. Bônus: um método que devolve a lista ordenada por artista com sorted(key=lambda m: m.artista). Teste adicionando 6 músicas (com pelo menos uma repetida) e confirme que o set elimina a repetição. Foco: juntar lista + comprehension + set com __hash__/__eq__ + ordenação numa coisa só.
Hoje organizamos objetos em coleções. Na próxima, damos um passo atrás: vamos DESENHAR as classes e suas relações ANTES de codar — o mapa antes da viagem.