Módulo 16 - Projeto final: agenda de contatos

Os métodos da agenda

11 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026

O que você vai aprender

  • Escrever adicionar_contato para incluir um contato na agenda.
  • Criar listar, devolvendo os contatos guardados.
  • Implementar buscar_por_nome com uma compreensão de lista.
  • Entender por que operar pela classe é melhor que mexer na lista por fora.

Adicionar e listar

Na aula anterior você colocou um contato na agenda com agenda.contatos.append(ana). Funciona, mas expõe a lista interna para o mundo. Quem usa a agenda não deveria precisar saber que, por dentro, ela guarda os contatos em uma lista chamada contatos. Métodos resolvem isso: eles dão à agenda um vocabulário próprio. Em vez de mexer na lista, você pede à agenda para adicionar. Se um dia a estrutura interna mudar, quem chama os métodos nem percebe.

class Agenda:
    def __init__(self):
        self.contatos = []

    def adicionar_contato(self, contato):
        self.contatos.append(contato)

    def listar(self):
        return list(self.contatos)

adicionar_contato inclui um contato; listar devolve uma cópia da lista.

adicionar_contato é curto de propósito: recebe um contato e o guarda. Poderia crescer depois, por exemplo salvando em arquivo a cada inclusão, sem que ninguém de fora precise mudar. Já listar devolve list(self.contatos), uma cópia nova da lista, e não a lista original. É uma proteção pequena e valiosa: quem recebe a lista pode percorrê-la à vontade sem risco de alterar por acidente os dados internos da agenda. Devolver e depois iterar deixa a impressão a cargo de quem chama.

Buscar com uma compreensão

Buscar um contato pelo nome é onde as compreensões brilham. A ideia é percorrer os contatos e ficar com os que batem com o nome procurado. Um detalhe importante de usabilidade: a busca deve ignorar maiúsculas e minúsculas, para que procurar por ana encontre Ana Souza. Fazemos isso comparando tudo em minúsculo com o método lower. Uma compreensão de lista expressa esse filtro em uma linha limpa.

    def buscar_por_nome(self, nome):
        encontrados = [
            c for c in self.contatos
            if nome.lower() in c.nome.lower()
        ]
        return encontrados[0] if encontrados else None


# Uso rapido
agenda = Agenda()
agenda.adicionar_contato(Contato("Ana Souza", "11999998888", "ana@exemplo.com"))
agenda.adicionar_contato(Contato("Bruno Lima", "11888887777"))

for contato in agenda.listar():
    print(contato)

print(agenda.buscar_por_nome("ana"))    # Ana Souza | 11999998888 | ana@exemplo.com
print(agenda.buscar_por_nome("carla"))  # None

A busca filtra com uma compreensão e devolve o primeiro encontrado, ou None.

Leia a compreensão como uma frase: para cada contato c na agenda, fique com ele se o nome procurado, em minúsculo, aparece dentro do nome do contato, em minúsculo. O in permite busca parcial, então mica encontra Micaela. No fim, o método devolve o primeiro da lista de encontrados, ou None se ninguém bateu. Esse None é uma escolha provisória. Ele funciona, mas obriga quem chama a lembrar de testar se veio None antes de usar. Na próxima aula, você troca esse None por algo mais expressivo: uma exceção própria, que avisa o problema em alto e bom som.

O ganho de operar pela classe

Repare no que mudou de qualidade. Antes, para usar a agenda, era preciso conhecer a sua tripa: a lista contatos e o método append das listas. Agora, a agenda oferece verbos claros: adicionar_contato, listar, buscar_por_nome. Quem usa a agenda conversa com ela nesse vocabulário e ignora como ela guarda as coisas por dentro. Esse princípio tem nome, encapsulamento, e é uma das maiores vantagens de organizar o programa em classes. O objeto esconde o como e oferece o quê.

Note também que os métodos não imprimem nada, com exceção do trecho de teste. Quem decide mostrar na tela é o código que usa a agenda, mais tarde o menu. Essa separação entre calcular e mostrar é o que permite, na aula de testes, verificar a agenda automaticamente: um teste chama buscar_por_nome e confere o que voltou, sem precisar ler a tela. Métodos que só imprimem seriam quase impossíveis de testar. Guardar essa disciplina agora rende muito lá na frente.

Teste rápido

Por que buscar_por_nome compara nome.lower() com c.nome.lower()?

Perguntas frequentes

Por que listar devolve list(self.contatos) e não self.contatos direto?
Para devolver uma cópia, não a lista interna. Assim, quem recebe pode percorrê-la sem risco de alterar por acidente os dados da agenda. É uma proteção barata contra bugs difíceis de achar, em que um trecho distante modifica a lista sem querer.
A busca parcial com in não pode trazer o contato errado?
Pode trazer mais de um, se vários nomes contiverem o texto. Por isso o método devolve o primeiro encontrado. Para uma agenda pequena e didática, isso basta. Um programa maior mostraria a lista de correspondências para o usuário escolher.
Poderia usar um laço for com append em vez da compreensão?
Sim, e o resultado seria o mesmo. A compreensão é preferida por ser mais curta e por deixar clara a intenção de filtrar em uma linha. É o jeito pythônico. Se a lógica ficasse complexa demais para uma linha, aí sim o laço explícito seria mais legível.
Por que devolver None quando não encontra, se depois vamos trocar?
Porque o projeto é incremental: primeiro uma versão simples que funciona, depois uma melhor. Devolver None é a solução mais direta e serve para ver a busca operando. Na aula 4 você percebe o problema dela e a substitui por uma exceção.
adicionar_contato deveria impedir contatos repetidos?
Poderia, e seria uma boa melhoria. Na versão do curso, mantemos simples: ele apenas adiciona. Evitar duplicatas é um dos exercícios sugeridos na última aula, usando buscar_por_nome antes de incluir.
O que significa encapsulamento, citado na aula?
É esconder os detalhes internos de um objeto e oferecer só uma interface clara. A agenda esconde que guarda contatos em uma lista e oferece métodos como adicionar_contato. Quem usa não precisa conhecer o interior, o que deixa o código mais fácil de mudar.

Fontes

Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.