Fundamentos do Python para Iniciantes

0/31 aulas0%
projeto

Projeto: Sistema de Cadastro Simples com Classes

Aprenda sobre projeto: sistema de cadastro simples com classes

90 min
Aula 6 de 6

🚀 Projeto: Sistema de Cadastro Simples com Classes

Olá, futuro desenvolvedor Python! 👋 Nesta aula prática, vamos consolidar tudo o que aprendemos sobre Orientação a Objetos (OOP) e Tratamento de Exceções construindo um sistema de cadastro simples. Este projeto nos permitirá aplicar conceitos como classes, objetos, encapsulamento e o uso de try-except para criar um programa robusto e interativo.


🎯 1. Introdução: O que vamos construir?

Nosso objetivo é desenvolver um pequeno sistema de cadastro de usuários via console. Ele permitirá:

  • Adicionar novos usuários (com nome e e-mail).
  • Listar todos os usuários cadastrados.
  • Buscar um usuário pelo nome.
  • Validar as entradas do usuário para garantir que os dados sejam consistentes.
  • Tratar erros de forma elegante, informando o usuário sobre o que deu errado.

Este projeto é uma excelente maneira de ver como os conceitos teóricos se unem para formar uma aplicação funcional. Vamos focar em boas práticas de código e na clareza da implementação.


📚 2. Explicação Detalhada com Exemplos

Vamos quebrar o projeto em partes menores para facilitar a compreensão e a implementação.

2.1. A Classe Usuario 🧑‍💻

Primeiro, precisamos definir como um "usuário" será representado em nosso sistema. Uma classe é a escolha perfeita para isso. Ela terá atributos como nome e email.

# usuario.py
class Usuario:
    """Representa um usuário com nome e email."""
 
    def __init__(self, nome: str, email: str):
        """
        Inicializa um novo objeto Usuario.
 
        Args:
            nome (str): O nome do usuário.
            email (str): O endereço de e-mail do usuário.
        """
        if not isinstance(nome, str) or not nome.strip():
            raise ValueError("O nome deve ser uma string não vazia.")
        if not isinstance(email, str) or "@" not in email or "." not in email:
            raise ValueError("O e-mail deve ser uma string válida e conter '@' e '.'.")
 
        self._nome = nome.strip()
        self._email = email.strip()
 
    @property
    def nome(self) -> str:
        """Retorna o nome do usuário."""
        return self._nome
 
    @property
    def email(self) -> str:
        """Retorna o email do usuário."""
        return self._email
 
    def __str__(self) -> str:
        """Retorna uma representação string do objeto Usuario."""
        return f"Nome: {self.nome}, E-mail: {self.email}"
 
    def __eq__(self, other) -> bool:
        """Compara se dois usuários são iguais com base no nome e email."""
        if not isinstance(other, Usuario):
            return NotImplemented
        return self.nome == other.nome and self.email == other.email
 
    def __hash__(self) -> int:
        """Retorna o hash do objeto para uso em coleções como sets ou dicionários."""
        return hash((self.nome, self.email))
 

Pontos Chave:

  • __init__: O construtor da classe. Ele recebe nome e email.
  • Validação no __init__: Usamos if e raise ValueError para garantir que os dados fornecidos são válidos no momento da criação do objeto. Isso é um exemplo de encapsulamento e validação de entrada.
  • Properties (@property): Usamos @property para permitir acesso aos atributos _nome e _email de forma controlada, como se fossem atributos públicos, mas sem permitir modificação direta após a criação (tornando-os "read-only" neste caso).
  • __str__: Define como o objeto será representado quando convertido para string (ex: print(usuario)).
  • __eq__ e __hash__: Boas práticas para permitir comparações de igualdade entre objetos e para que objetos Usuario possam ser usados em conjuntos (set) ou como chaves de dicionário.

2.2. A Classe SistemaCadastro 🏢

Esta classe será responsável por gerenciar a coleção de usuários e as operações de cadastro.

# sistema_cadastro.py
from typing import List, Optional
from usuario import Usuario
 
class SistemaCadastro:
    """Gerencia o cadastro de usuários."""
 
    def __init__(self):
        """Inicializa o sistema de cadastro com uma lista vazia de usuários."""
        self._usuarios: List[Usuario] = []
 
    def adicionar_usuario(self, nome: str, email: str) -> None:
        """
        Adiciona um novo usuário ao sistema.
 
        Args:
            nome (str): O nome do usuário.
            email (str): O endereço de e-mail do usuário.
 
        Raises:
            ValueError: Se o usuário já existir ou os dados forem inválidos.
        """
        try:
            novo_usuario = Usuario(nome, email)
            if novo_usuario in self._usuarios:
                raise ValueError(f"Usuário com email '{email}' já cadastrado.")
            self._usuarios.append(novo_usuario)
            print(f"✅ Usuário '{nome}' adicionado com sucesso!")
        except ValueError as e:
            print(f"❌ Erro ao adicionar usuário: {e}")
 
    def listar_usuarios(self) -> None:
        """Lista todos os usuários cadastrados no sistema."""
        if not self._usuarios:
            print("Nenhum usuário cadastrado ainda.")
            return
 
        print("\n--- Usuários Cadastrados ---")
        for i, usuario in enumerate(self._usuarios):
            print(f"{i+1}. {usuario}")
        print("----------------------------\n")
 
    def buscar_usuario(self, nome: str) -> Optional[Usuario]:
        """
        Busca um usuário pelo nome (case-insensitive).
 
        Args:
            nome (str): O nome a ser buscado.
 
        Returns:
            Optional[Usuario]: O objeto Usuario se encontrado, None caso contrário.
        """
        nome_lower = nome.lower()
        for usuario in self._usuarios:
            if usuario.nome.lower() == nome_lower:
                return usuario
        return None
 

Pontos Chave:

  • _usuarios: Uma lista privada (_) para armazenar objetos Usuario.
  • adicionar_usuario:
    • Tenta criar um Usuario. Se a validação na classe Usuario falhar, um ValueError é levantado.
    • Verifica se o usuário já existe na lista antes de adicionar.
    • Usa um bloco try-except para capturar ValueErrors, sejam eles da criação do Usuario ou da verificação de duplicidade. Isso é tratamento de exceções em ação!
  • listar_usuarios: Itera sobre a lista e imprime os detalhes de cada usuário.
  • buscar_usuario: Itera sobre a lista para encontrar um usuário pelo nome, ignorando maiúsculas/minúsculas.

2.3. O Loop Principal do Programa (Interface) 🖥️

Agora, vamos juntar tudo em um script principal que cria uma interface de console para o usuário interagir com o sistema.

# main.py
from sistema_cadastro import SistemaCadastro
 
def exibir_menu():
    """Exibe o menu de opções para o usuário."""
    print("\n--- Sistema de Cadastro ---")
    print("1. Adicionar Usuário")
    print("2. Listar Usuários")
    print("3. Buscar Usuário")
    print("4. Sair")
    print("---------------------------\n")
 
def main():
    """Função principal que executa o sistema de cadastro."""
    sistema = SistemaCadastro()
 
    while True:
        exibir_menu()
        escolha = input("Escolha uma opção: ")
 
        if escolha == '1':
            print("\n--- Adicionar Novo Usuário ---")
            nome = input("Digite o nome do usuário: ")
            email = input("Digite o e-mail do usuário: ")
            sistema.adicionar_usuario(nome, email)
        elif escolha == '2':
            sistema.listar_usuarios()
        elif escolha == '3':
            print("\n--- Buscar Usuário ---")
            nome_busca = input("Digite o nome do usuário para buscar: ")
            usuario_encontrado = sistema.buscar_usuario(nome_busca)
            if usuario_encontrado:
                print(f"✅ Usuário encontrado: {usuario_encontrado}")
            else:
                print(f"❌ Usuário com nome '{nome_busca}' não encontrado.")
        elif escolha == '4':
            print("Saindo do sistema. Até mais! 👋")
            break
        else:
            print("Opção inválida. Por favor, escolha novamente.")
 
if __name__ == "__main__":
    main()
 

Pontos Chave:

  • exibir_menu: Função simples para mostrar as opções disponíveis.
  • main: A função principal do programa.
    • Cria uma instância de SistemaCadastro.
    • Usa um loop while True para manter o programa em execução até que o usuário escolha sair.
    • Lê a escolha do usuário e chama o método apropriado do sistema.
    • Tratamento de Exceções Implícito: As chamadas a sistema.adicionar_usuario já contêm seus próprios try-except, então a main não precisa de um try-except global para essa operação específica. Isso demonstra como as responsabilidades podem ser distribuídas.

3. Código de Exemplo e Boas Práticas (Documentação Oficial) 🐍

O código acima segue as melhores práticas e convenções da linguagem Python, conforme sugerido pela PEP 8 - Style Guide for Python Code.

Alguns pontos importantes que aplicamos:

  • Nomenclatura: Nomes de classes em CamelCase (Usuario, SistemaCadastro), nomes de funções e variáveis em snake_case (adicionar_usuario, _usuarios).
  • Docstrings: Usamos docstrings ("""Docstring""") para explicar o propósito de classes, métodos e funções, incluindo seus argumentos (Args) e o que retornam (Returns). Isso é crucial para a legibilidade e manutenção do código. Veja a PEP 257 - Docstring Conventions.
  • Type Hinting: Utilizamos anotações de tipo (nome: str, -> None, List[Usuario]) para indicar os tipos esperados de argumentos e retornos. Isso melhora a clareza do código e permite ferramentas de análise estática (como MyPy) verificarem possíveis erros. Mais sobre isso na PEP 484 - Type Hints.
  • Tratamento de Exceções: A forma como usamos try-except para capturar e lidar com erros é um padrão recomendado. A documentação oficial de Python sobre tratamento de exceções é um ótimo recurso.
  • Encapsulamento: O uso de _ (underscore) antes de _nome, _email e _usuarios indica que esses atributos são "protegidos" ou "internos" à classe, não devendo ser acessados diretamente de fora. Isso é uma convenção, não uma restrição forte em Python.

🛠️ 4. Integração de Conceitos

Neste projeto, você viu a integração perfeita de vários conceitos que estudamos:

  • Programação Orientada a Objetos (OOP):
    • Classes e Objetos: Usuario e SistemaCadastro são classes que criam objetos para representar entidades do mundo real.
    • Encapsulamento: Atributos internos (_nome, _email, _usuarios) são protegidos e acessados via métodos ou properties, controlando como os dados são manipulados.
    • Abstração: As classes escondem os detalhes complexos de implementação, oferecendo uma interface simples para interagir (ex: sistema.adicionar_usuario()).
  • Tratamento de Exceções:
    • raise: Usado para levantar ValueError quando a validação de dados falha (ex: Usuario.__init__).
    • try-except: Usado para capturar e lidar com essas exceções de forma controlada, evitando que o programa trave e fornecendo feedback útil ao usuário (ex: SistemaCadastro.adicionar_usuario).
  • Estruturas de Dados: Uma list (_usuarios) é usada para armazenar a coleção de objetos Usuario.
  • Fluxo de Controle: if-elif-else para o menu, while para o loop principal.

📝 5. Exercícios/Desafios

Agora é a sua vez de colocar a mão na massa! 🚀

  1. Baixe o código: Crie os arquivos usuario.py, sistema_cadastro.py e main.py e copie o código fornecido.
  2. Execute o programa: Rode python main.py no seu terminal e interaja com o sistema. Teste adicionar usuários válidos e inválidos.
  3. Implemente a remoção de usuário:
    • Adicione uma nova opção no menu (5. Remover Usuário).
    • No SistemaCadastro, crie um método remover_usuario(email: str) que:
      • Itere sobre a lista de usuários.
      • Encontre o usuário pelo e-mail.
      • Remova o usuário da lista.
      • Se o usuário não for encontrado, imprima uma mensagem de erro.
      • Se encontrado e removido, imprima uma mensagem de sucesso.
    • No main.py, adicione a lógica para chamar remover_usuario quando a opção 5 for escolhida.
  4. Permitir edição de e-mail:
    • No Usuario classe, adicione um setter para o email (@email.setter) que também valida o novo e-mail.
    • Adicione uma nova opção no menu (6. Editar E-mail do Usuário).
    • No SistemaCadastro, crie um método editar_email_usuario(nome: str, novo_email: str) que:
      • Busque o usuário pelo nome.
      • Se encontrado, use o setter para atualizar o e-mail.
      • Use try-except para lidar com possíveis ValueErrors do setter.
  5. Persistência de dados (Desafio Avançado):
    • Em vez de perder todos os dados ao fechar o programa, salve a lista de usuários em um arquivo (ex: usuarios.txt ou usuarios.json).
    • Ao iniciar o programa, carregue os usuários desse arquivo.
    • Use os módulos json ou csv do Python para isso. Lembre-se de que você precisará converter objetos Usuario para dicionários (e vice-versa) para salvar/carregar.

💡 6. Resumo e Próximos Passos

Parabéns! 🎉 Você acabou de construir um sistema funcional que integra os conceitos mais importantes de OOP e tratamento de exceções em Python.

Nesta aula, você:

  • Projetou e implementou classes (Usuario, SistemaCadastro) para modelar entidades.
  • Aplicou o encapsulamento e a validação de dados usando __init__ e properties.
  • Utilizou try-except para criar um programa mais robusto e amigável.
  • Construiu uma interface de console interativa para o usuário.
  • Seguiu boas práticas de codificação Python (PEP 8, docstrings, type hinting).

Próximos Passos:

  • Refatoração: Sempre procure maneiras de melhorar seu código, tornando-o mais limpo, eficiente e legível.
  • Testes Unitários: Aprenda a escrever testes para suas classes e funções. Isso garante que seu código funcione como esperado e ajuda a prevenir regressões.
  • Outras Estruturas de Dados: Explore como outras estruturas de dados (como dicionários) poderiam ser usadas para armazenar usuários, talvez usando o e-mail como chave para busca mais rápida.
  • Interfaces Gráficas (GUI): Se você gostou de construir aplicações, considere explorar frameworks como Tkinter, PyQt ou Kivy para criar interfaces mais visuais.
  • Frameworks Web: Para sistemas de cadastro mais complexos e acessíveis via navegador, frameworks como Flask ou Django são os próximos passos naturais.

Continue praticando, e você se tornará um mestre em Python! 💪

© 2025 Escola All Dev. Todos os direitos reservados.

Projeto: Sistema de Cadastro Simples com Classes - Fundamentos do Python para Iniciantes | escola.all.dev.br