diff --git a/modulo-01/paulo/ex01.py b/modulo-01/paulo/ex01.py new file mode 100644 index 0000000..bf9b9b0 --- /dev/null +++ b/modulo-01/paulo/ex01.py @@ -0,0 +1,3 @@ +print("Olá, Mundo!") +print("Paulo") +print("Python: simples, poderoso e elegante.") diff --git a/modulo-01/paulo/ex02.py b/modulo-01/paulo/ex02.py new file mode 100644 index 0000000..3016dcb --- /dev/null +++ b/modulo-01/paulo/ex02.py @@ -0,0 +1,4 @@ +import sys + +print(f"Versão do Python: {sys.version}") +print(f"Sistema Operacional: {sys.platform}") diff --git a/modulo-01/paulo/ex03.py b/modulo-01/paulo/ex03.py new file mode 100644 index 0000000..e8ec822 --- /dev/null +++ b/modulo-01/paulo/ex03.py @@ -0,0 +1,5 @@ +import this + +# Abaixo do import, adicione um comentário explicando com suas palavras um dos princípios que mais fez sentido para você. +# "Simples é melhor que complexo." +# Esse princípio é muito importante porque um código simples é mais fácil de entender, manter e corrigir do que um código desnecessariamente complexo. diff --git a/modulo-01/paulo/ex04.py b/modulo-01/paulo/ex04.py new file mode 100644 index 0000000..c31c2f0 --- /dev/null +++ b/modulo-01/paulo/ex04.py @@ -0,0 +1,20 @@ +""" +Este script inicializa os dados de um funcionário e os exibe no console. +Ele demonstra a criação de variáveis de diferentes tipos (string, int, float e bool) +e o uso da função print para saída de dados. +""" + +# Variável que armazena o nome da pessoa (tipo string) +nome = "Ana Lima" + +# Variável que armazena a idade da pessoa (tipo inteiro) +idade = 29 + +# Variável que armazena o salário da pessoa (tipo float) +salario = 4500.00 + +# Variável que armazena o status de atividade da pessoa (tipo booleano) +ativo = True + +# Imprime os valores das variáveis na tela, separados por espaço +print(nome, idade, salario, ativo) diff --git a/modulo-01/paulo/ex05.py b/modulo-01/paulo/ex05.py new file mode 100644 index 0000000..3cfc217 --- /dev/null +++ b/modulo-01/paulo/ex05.py @@ -0,0 +1,11 @@ +# Print("Bem-vindo ao curso de Python") # Erro 1: A função correta é 'print' com 'p' minúsculo +print("Bem-vindo ao curso de Python") + +# nome = "Carlos # Erro 2: Faltou fechar as aspas duplas na string +nome = "Carlos" + +# print("Aluno: " + nome) # Correto +print("Aluno: " + nome) + +# print(Curso de Python) # Erro 3: O texto precisa estar entre aspas para ser reconhecido como string +print("Curso de Python") diff --git a/modulo-01/paulo/ex06.py b/modulo-01/paulo/ex06.py new file mode 100644 index 0000000..76e55d1 --- /dev/null +++ b/modulo-01/paulo/ex06.py @@ -0,0 +1,13 @@ +ano_atual = 2025 +temperatura_celsius = 28.5 +cidade = "São Paulo" +chovendo = False +previsao = None +vazia = "" + +print(f"{ano_atual} → {type(ano_atual)}") +print(f"{temperatura_celsius} → {type(temperatura_celsius)}") +print(f"{cidade} → {type(cidade)}") +print(f"{chovendo} → {type(chovendo)}") +print(f"{previsao} → {type(previsao)}") +print(f"'{vazia}' → {type(vazia)}") diff --git a/modulo-01/paulo/ex07.py b/modulo-01/paulo/ex07.py new file mode 100644 index 0000000..6db58ed --- /dev/null +++ b/modulo-01/paulo/ex07.py @@ -0,0 +1,6 @@ +largura = 12.5 +comprimento = 30.0 + +area = largura * comprimento + +print(f"Área do terreno: {area:.1f} m²") diff --git a/modulo-01/paulo/ex08.py b/modulo-01/paulo/ex08.py new file mode 100644 index 0000000..62d7f20 --- /dev/null +++ b/modulo-01/paulo/ex08.py @@ -0,0 +1,8 @@ +celsius = 36.5 + +fahrenheit = (celsius * 9/5) + 32 +kelvin = celsius + 273.15 + +print(f"Temperatura em Celsius: {celsius:.1f}°C") +print(f"Temperatura em Fahrenheit: {fahrenheit:.1f}°F") +print(f"Temperatura em Kelvin: {kelvin:.2f}K") diff --git a/modulo-01/paulo/ex09.py b/modulo-01/paulo/ex09.py new file mode 100644 index 0000000..5fbbb5b --- /dev/null +++ b/modulo-01/paulo/ex09.py @@ -0,0 +1,9 @@ +import datetime + +nome = input("Digite seu nome: ") +idade = int(input("Digite sua idade: ")) + +ano_atual = datetime.datetime.now().year +ano_nascimento = ano_atual - idade + +print(f"Olá, {nome}! Você tem {idade} anos e nasceu por volta de {ano_nascimento}.") diff --git a/modulo-01/paulo/ex10.py b/modulo-01/paulo/ex10.py new file mode 100644 index 0000000..8d3c6e2 --- /dev/null +++ b/modulo-01/paulo/ex10.py @@ -0,0 +1,8 @@ +capacidade_caminhao = 850 +peso_caixa = 32 + +caixas_completas = capacidade_caminhao // peso_caixa +peso_restante = capacidade_caminhao % peso_caixa + +print(f"Cabem {caixas_completas} caixas completas no caminhão.") +print(f"O peso restante que não completa uma caixa é de {peso_restante} kg.") diff --git a/modulo-01/paulo/ex11.py b/modulo-01/paulo/ex11.py new file mode 100644 index 0000000..540a52c --- /dev/null +++ b/modulo-01/paulo/ex11.py @@ -0,0 +1,15 @@ +nome = "Mariana Souza" +cargo = "Analista de Dados" +salario = 7850.50 +anos = 3 + +salario_formatado = f"{salario:,.2f}".replace(",", "_").replace(".", ",").replace("_", ".") + +print("=============================") +print(" FICHA DO FUNCIONÁRIO ") +print("=============================") +print(f"Nome : {nome}") +print(f"Cargo : {cargo}") +print(f"Salário: R$ {salario_formatado}") +print(f"Tempo : {anos} ano(s) de empresa") +print("=============================") diff --git a/modulo-01/paulo/ex12.py b/modulo-01/paulo/ex12.py new file mode 100644 index 0000000..8fce840 --- /dev/null +++ b/modulo-01/paulo/ex12.py @@ -0,0 +1,6 @@ +peso = float(input("Digite o seu peso (kg): ")) +altura = float(input("Digite a sua altura (m): ")) + +imc = peso / (altura ** 2) + +print(f"O seu IMC é de {imc:.2f}.") diff --git a/modulo-01/paulo/ex13.py b/modulo-01/paulo/ex13.py new file mode 100644 index 0000000..0620b66 --- /dev/null +++ b/modulo-01/paulo/ex13.py @@ -0,0 +1,8 @@ +numero1 = 150 +numero2 = 80 + +print(f"O primeiro número é maior que o segundo? {numero1 > numero2}") +print(f"Os dois são iguais? {numero1 == numero2}") +print(f"Ambos são positivos? {numero1 > 0 and numero2 > 0}") +print(f"Pelo menos um é maior que 100? {numero1 > 100 or numero2 > 100}") +print(f"O primeiro é diferente de zero? {numero1 != 0}") diff --git a/modulo-01/paulo/ex14.py b/modulo-01/paulo/ex14.py new file mode 100644 index 0000000..f54e065 --- /dev/null +++ b/modulo-01/paulo/ex14.py @@ -0,0 +1,15 @@ +# Forma 1: Com variável auxiliar +a = 10 +b = 20 + +aux = a +a = b +b = aux +print("Forma 1:", a, b) + +# Forma 2: Método idiomático do Python (desempacotamento) +a = 10 +b = 20 + +a, b = b, a +print("Forma 2:", a, b) diff --git a/modulo-01/paulo/ex15.py b/modulo-01/paulo/ex15.py new file mode 100644 index 0000000..aaf60b6 --- /dev/null +++ b/modulo-01/paulo/ex15.py @@ -0,0 +1,7 @@ +valor_compra = float(input("Digite o valor da compra (R$): ")) + +desconto = valor_compra * 0.10 +valor_final = valor_compra - desconto + +print(f"Desconto de 10%: R$ {desconto:.2f}") +print(f"Valor final a pagar: R$ {valor_final:.2f}") diff --git a/modulo-01/paulo/ex16.py b/modulo-01/paulo/ex16.py new file mode 100644 index 0000000..9c8fdcc --- /dev/null +++ b/modulo-01/paulo/ex16.py @@ -0,0 +1,8 @@ +import math + +x1, y1 = 3, 4 +x2, y2 = 7, 1 + +distancia = math.sqrt((x2 - x1)**2 + (y2 - y1)**2) + +print(f"A distância entre os pontos é: {distancia:.4f}") diff --git a/modulo-01/paulo/ex17.py b/modulo-01/paulo/ex17.py new file mode 100644 index 0000000..7cecf7e --- /dev/null +++ b/modulo-01/paulo/ex17.py @@ -0,0 +1,16 @@ +descricao = input("Descrição do produto: ") +qtd = int(input("Quantidade: ")) +preco = float(input("Preço unitário: ")) + +subtotal = qtd * preco +imposto = subtotal * 0.12 +total = subtotal + imposto + +print("\n===== NOTA FISCAL =====") +print(f"Produto : {descricao}") +print(f"Quantidade: {qtd} unidade(s)") +print(f"Preço Unit: R$ {preco:.2f}") +print(f"Subtotal : R$ {subtotal:.2f}") +print(f"Imposto : R$ {imposto:.2f}") +print(f"Total : R$ {total:.2f}") +print("=======================") diff --git a/modulo-01/paulo/ex18.py b/modulo-01/paulo/ex18.py new file mode 100644 index 0000000..98f8dcc --- /dev/null +++ b/modulo-01/paulo/ex18.py @@ -0,0 +1,15 @@ +metros = float(input("Digite uma distância em metros: ")) + +km = metros / 1000 +cm = metros * 100 +mm = metros * 1000 +polegadas = metros * 39.3701 +pes = metros * 3.28084 + +print(f"{'Metros':<15} | {metros:>10.2f}") +print("-" * 30) +print(f"{'Quilômetros':<15} | {km:>10.4f}") +print(f"{'Centímetros':<15} | {cm:>10.2f}") +print(f"{'Milímetros':<15} | {mm:>10.2f}") +print(f"{'Polegadas':<15} | {polegadas:>10.2f}") +print(f"{'Pés':<15} | {pes:>10.2f}") diff --git a/modulo-01/paulo/ex19.py b/modulo-01/paulo/ex19.py new file mode 100644 index 0000000..5744fc2 --- /dev/null +++ b/modulo-01/paulo/ex19.py @@ -0,0 +1,11 @@ +email_bruto = " joao.silva@EMPRESA.com.br " + +email_limpo = email_bruto.strip().lower() + +partes = email_limpo.split('@') +usuario = partes[0] +dominio = partes[1] + +print(f"E-mail limpo: {email_limpo}") +print(f"Usuário: {usuario}") +print(f"Domínio: {dominio}") diff --git a/modulo-01/paulo/ex20.py b/modulo-01/paulo/ex20.py new file mode 100644 index 0000000..1be8a78 --- /dev/null +++ b/modulo-01/paulo/ex20.py @@ -0,0 +1,12 @@ +capital = float(input("Capital inicial: ")) +taxa = float(input("Taxa de juros ao mês (%): ")) +meses = int(input("Período em meses: ")) + +montante = capital * (1 + (taxa / 100) * meses) +juros_totais = montante - capital + +print(f"\nCapital : R$ {capital:.2f}") +print(f"Taxa : {taxa:.2f}% ao mês") +print(f"Período : {meses} meses") +print(f"Juros : R$ {juros_totais:.2f}") +print(f"Montante : R$ {montante:.2f}") diff --git a/modulo-01/paulo/ex21.py b/modulo-01/paulo/ex21.py new file mode 100644 index 0000000..b9a006c --- /dev/null +++ b/modulo-01/paulo/ex21.py @@ -0,0 +1,19 @@ +def saudacao(nome): + """ + Retorna uma mensagem de boas-vindas personalizada. + + Args: + nome (str): Nome da pessoa a ser saudada. + + Returns: + str: String com a mensagem de boas-vindas. + + Example: + >>> saudacao("Ana") + 'Olá, Ana! Seja bem-vinda ao curso.' + """ + return f"Olá, {nome}! Seja bem-vinda ao curso." + +print(saudacao("Maria")) +print(saudacao("João")) +print(saudacao("Carlos")) diff --git a/modulo-01/paulo/ex22.py b/modulo-01/paulo/ex22.py new file mode 100644 index 0000000..662a781 --- /dev/null +++ b/modulo-01/paulo/ex22.py @@ -0,0 +1,8 @@ +def calcular_area(largura: float, altura: float) -> float: + return largura * altura + +def formatar_nome(nome: str, sobrenome: str) -> str: + return f"{nome} {sobrenome}".title() + +def eh_maior_de_idade(idade: int) -> bool: + return idade >= 18 diff --git a/modulo-01/paulo/ex23.py b/modulo-01/paulo/ex23.py new file mode 100644 index 0000000..a15b44b --- /dev/null +++ b/modulo-01/paulo/ex23.py @@ -0,0 +1,19 @@ +import json + +aluno = { + "nome": "Pedro Henrique", + "idade": 22, + "curso": "Full Stack", + "ativo": True, + "notas": [8.5, 9.0, 7.5] +} + +json_str = json.dumps(aluno, indent=2) +print("JSON string:") +print(json_str) + +aluno_lido = json.loads(json_str) +media = sum(aluno_lido["notas"]) / len(aluno_lido["notas"]) + +print(f"\nNome: {aluno_lido['nome']}") +print(f"Média das notas: {media:.2f}") diff --git a/modulo-01/paulo/ex24.py b/modulo-01/paulo/ex24.py new file mode 100644 index 0000000..c9664db --- /dev/null +++ b/modulo-01/paulo/ex24.py @@ -0,0 +1,23 @@ +from typing import Tuple + +def converter_moeda(valor_reais: float) -> Tuple[float, float]: + """ + Converte um valor em reais para dólar e euro. + + Args: + valor_reais (float): O valor em reais (BRL) a ser convertido. + + Returns: + Tuple[float, float]: Uma tupla contendo o valor em dólares (USD) e em euros (EUR). + + Example: + >>> converter_moeda(100.0) + (19.41747572815534, 17.92114695340502) + """ + cotacao_usd = 5.15 + cotacao_eur = 5.58 + + usd = valor_reais / cotacao_usd + eur = valor_reais / cotacao_eur + + return usd, eur diff --git a/modulo-01/paulo/ex25.py b/modulo-01/paulo/ex25.py new file mode 100644 index 0000000..dfc8e8b --- /dev/null +++ b/modulo-01/paulo/ex25.py @@ -0,0 +1,25 @@ +import json + +produto = { + "id": 101, + "nome": "Teclado Mecânico", + "preco": 350.00, + "estoque": 25, + "disponivel": True, + "categorias": ["Periféricos", "Informática", "Gamer"] +} + +# Salva em produto.json +with open("produto.json", "w", encoding="utf-8") as f: + json.dump(produto, f, indent=4, ensure_ascii=False) + +# Lê de produto.json +with open("produto.json", "r", encoding="utf-8") as f: + produto_lido = json.load(f) + +print("ID:", produto_lido["id"]) +print("Nome:", produto_lido["nome"]) +print("Preço:", produto_lido["preco"]) +print("Estoque:", produto_lido["estoque"]) +print("Disponível:", produto_lido["disponivel"]) +print("Categorias:", ", ".join(produto_lido["categorias"])) diff --git a/modulo-01/paulo/ex26.py b/modulo-01/paulo/ex26.py new file mode 100644 index 0000000..800aca0 --- /dev/null +++ b/modulo-01/paulo/ex26.py @@ -0,0 +1,25 @@ +from typing import Optional, Union, Dict, Any + +def buscar_usuario(id_usuario: int, nome: Union[str, None] = None) -> Optional[Dict[str, Any]]: + """ + Busca os dados de um usuário pelo ID e nome. + + Args: + id_usuario (int): O ID do usuário. Se for negativo, a função retorna None. + nome (Union[str, None], opcional): O nome do usuário. Padrão é None. + + Returns: + Optional[Dict[str, Any]]: Um dicionário com os dados do usuário se o ID for válido, + ou None caso o ID seja negativo. + """ + if id_usuario < 0: + return None + + return { + "id": id_usuario, + "nome": nome, + "status": "ativo" + } + +print("ID Positivo:", buscar_usuario(1, "Ana")) +print("ID Negativo:", buscar_usuario(-5, "Carlos")) diff --git a/modulo-01/paulo/ex27.py b/modulo-01/paulo/ex27.py new file mode 100644 index 0000000..94e3bb5 --- /dev/null +++ b/modulo-01/paulo/ex27.py @@ -0,0 +1,24 @@ +import json + +funcionarios = [ + {"nome": "Carlos", "cargo": "Desenvolvedor", "salario": 5000.00, "departamento": "TI"}, + {"nome": "Ana", "cargo": "Gerente", "salario": 8500.00, "departamento": "TI"}, + {"nome": "João", "cargo": "Suporte", "salario": 3200.00, "departamento": "Operações"} +] + +with open("funcionarios.json", "w", encoding="utf-8") as f: + json.dump(funcionarios, f, indent=4, ensure_ascii=False) + +with open("funcionarios.json", "r", encoding="utf-8") as f: + dados_lidos = json.load(f) + +print(f"{'NOME':<15} | {'CARGO':<15} | {'DEPARTAMENTO':<15} | {'SALÁRIO':<10}") +print("-" * 65) +soma_salarios = 0 +for func in dados_lidos: + soma_salarios += func['salario'] + print(f"{func['nome']:<15} | {func['cargo']:<15} | {func['departamento']:<15} | R$ {func['salario']:>8.2f}") + +print("-" * 65) +media_salario = soma_salarios / len(dados_lidos) +print(f"Salário Médio da equipe: R$ {media_salario:.2f}") diff --git a/modulo-01/paulo/ex28.py b/modulo-01/paulo/ex28.py new file mode 100644 index 0000000..05d8c10 --- /dev/null +++ b/modulo-01/paulo/ex28.py @@ -0,0 +1,25 @@ +def calcular_juros_compostos(capital: float, taxa: float, periodo: int) -> float: + """ + Calcula o montante final usando juros compostos. + + Args: + capital (float): O valor do capital inicial. + taxa (float): A taxa de juros (em porcentagem). + periodo (int): O número de períodos de tempo. + + Returns: + float: O montante final após a aplicação dos juros compostos. + + Raises: + ValueError: Se o capital ou a taxa forem negativos. + + Example: + >>> calcular_juros_compostos(1000.0, 5.0, 12) + 1795.85632602213 + """ + if capital < 0 or taxa < 0: + raise ValueError("Capital e taxa não podem ser negativos.") + + return capital * (1 + taxa / 100) ** periodo + +print(calcular_juros_compostos(1000.0, 5.0, 12)) diff --git a/modulo-01/paulo/ex29.py b/modulo-01/paulo/ex29.py new file mode 100644 index 0000000..d7e7769 --- /dev/null +++ b/modulo-01/paulo/ex29.py @@ -0,0 +1,29 @@ +import json + +resposta_api = """ +{ + "cidade": "Manaus", + "pais": "BR", + "temperatura": { + "atual": 32.4, + "minima": 26.1, + "maxima": 35.8, + "sensacao": 38.2 + }, + "umidade": 87, + "condicao": "Parcialmente nublado", + "vento": { "velocidade_kmh": 12, "direcao": "NE" }, + "atualizado_em": "2025-01-15T14:30:00" +} +""" + +dados = json.loads(resposta_api) + +print(f"Boletim Meteorológico - {dados['cidade']}, {dados['pais']}") +print(f"Atualizado em: {dados['atualizado_em']}") +print("-" * 35) +print(f"Temperatura atual: {dados['temperatura']['atual']}°C (Sensação de {dados['temperatura']['sensacao']}°C)") +print(f"Mínima: {dados['temperatura']['minima']}°C | Máxima: {dados['temperatura']['maxima']}°C") +print(f"Condição: {dados['condicao']}") +print(f"Umidade: {dados['umidade']}%") +print(f"Vento: {dados['vento']['velocidade_kmh']} km/h direção {dados['vento']['direcao']}") diff --git a/modulo-01/paulo/ex30.py b/modulo-01/paulo/ex30.py new file mode 100644 index 0000000..6ae22af --- /dev/null +++ b/modulo-01/paulo/ex30.py @@ -0,0 +1,30 @@ +import json +from typing import TypedDict, List + +class ItemPedido(TypedDict): + produto: str + quantidade: int + preco_unitario: float + +class Pedido(TypedDict): + id_pedido: int + cliente: str + itens: List[ItemPedido] + status: str + +# Criando um pedido de exemplo +pedido_exemplo: Pedido = { + "id_pedido": 12345, + "cliente": "Marcos Silva", + "itens": [ + {"produto": "Mousepad", "quantidade": 2, "preco_unitario": 45.90}, + {"produto": "Teclado", "quantidade": 1, "preco_unitario": 299.90} + ], + "status": "Em processamento" +} + +# Serializando para JSON +pedido_json = json.dumps(pedido_exemplo, indent=4, ensure_ascii=False) + +print("Pedido Serializado:") +print(pedido_json) diff --git a/modulo-01/paulo/ex31.py b/modulo-01/paulo/ex31.py new file mode 100644 index 0000000..7a895c2 --- /dev/null +++ b/modulo-01/paulo/ex31.py @@ -0,0 +1,23 @@ +import json + +cadastro = {"id": 1042, "nome": "Fernanda Costa", "email": "fernanda@empresa.com"} +perfil = {"id": 1042, "cargo": "Engenheira de Software", "nivel": "Senior", + "salario": 12500.00, "habilidades": ["Python", "Django", "PostgreSQL"]} + +# Mesclando dicionários +funcionario_completo = {**cadastro, **perfil} + +# Salva em JSON +with open("funcionario_completo.json", "w", encoding="utf-8") as f: + json.dump(funcionario_completo, f, indent=4, ensure_ascii=False) + +# Lê e exibe formatado +with open("funcionario_completo.json", "r", encoding="utf-8") as f: + dados = json.load(f) + +print(f"Funcionário: {dados['nome']} ({dados['email']})") +print(f"Cargo: {dados['nivel']} {dados['cargo']}") +print(f"Salário: R$ {dados['salario']:.2f}") +print("Habilidades:") +for i, habilidade in enumerate(dados['habilidades'], start=1): + print(f" {i}. {habilidade}") diff --git a/modulo-01/paulo/ex32.py b/modulo-01/paulo/ex32.py new file mode 100644 index 0000000..3960afa --- /dev/null +++ b/modulo-01/paulo/ex32.py @@ -0,0 +1,45 @@ +from typing import Dict, List, Any + +def validar_cadastro(dados: Dict[str, Any]) -> Dict[str, List[str]]: + """ + Valida um dicionário de dados de cadastro. + + Args: + dados (Dict[str, Any]): Dicionário com dados do cadastro. + + Returns: + Dict[str, List[str]]: Resultado contendo listas de campos válidos e erros. + """ + resultado: Dict[str, List[str]] = {"valido": [], "erros": []} + + nome = dados.get("nome", "") + if isinstance(nome, str) and len(nome) >= 3: + resultado["valido"].append("nome") + else: + resultado["erros"].append("Nome inválido (deve ter >= 3 caracteres)") + + email = dados.get("email", "") + if isinstance(email, str) and "@" in email and "." in email: + resultado["valido"].append("email") + else: + resultado["erros"].append("E-mail inválido") + + idade = dados.get("idade", 0) + if isinstance(idade, (int, float)) and 18 <= idade <= 120: + resultado["valido"].append("idade") + else: + resultado["erros"].append("Idade inválida (entre 18 e 120)") + + cpf = dados.get("cpf", "") + if isinstance(cpf, str) and len(cpf) == 11 and cpf.isdigit(): + resultado["valido"].append("cpf") + else: + resultado["erros"].append("CPF inválido (11 dígitos numéricos)") + + return resultado + +validos = {"nome": "Ana", "email": "ana@teste.com", "idade": 25, "cpf": "12345678901"} +invalidos = {"nome": "Z", "email": "anateste.com", "idade": 15, "cpf": "123"} + +print("Válidos:", validar_cadastro(validos)) +print("Inválidos:", validar_cadastro(invalidos)) diff --git a/modulo-01/paulo/ex33.py b/modulo-01/paulo/ex33.py new file mode 100644 index 0000000..ec4e987 --- /dev/null +++ b/modulo-01/paulo/ex33.py @@ -0,0 +1,43 @@ +import json +from datetime import datetime +import os + +def registrar_evento(arquivo: str, nivel: str, mensagem: str) -> None: + """Registra um log.""" + logs = ler_logs(arquivo) + logs.append({ + "timestamp": datetime.now().isoformat(), + "nivel": nivel, + "mensagem": mensagem + }) + with open(arquivo, "w", encoding="utf-8") as f: + json.dump(logs, f, indent=4) + +def ler_logs(arquivo: str) -> list: + """Lê os logs.""" + if not os.path.exists(arquivo): + return [] + with open(arquivo, "r", encoding="utf-8") as f: + try: + return json.load(f) + except json.JSONDecodeError: + return [] + +def filtrar_por_nivel(logs: list, nivel: str) -> list: + """Filtra os logs por nível.""" + return [log for log in logs if log["nivel"] == nivel] + +arquivo_log = "sistema.log.json" +if os.path.exists(arquivo_log): + os.remove(arquivo_log) + +registrar_evento(arquivo_log, "INFO", "Sistema iniciado") +registrar_evento(arquivo_log, "INFO", "Conectado") +registrar_evento(arquivo_log, "WARNING", "Atenção") +registrar_evento(arquivo_log, "ERROR", "Falha crítica") +registrar_evento(arquivo_log, "INFO", "Fim") + +logs = ler_logs(arquivo_log) +print("Total logs:", len(logs)) +print("INFO logs:", len(filtrar_por_nivel(logs, "INFO"))) +print("ERROR logs:", len(filtrar_por_nivel(logs, "ERROR"))) diff --git a/modulo-01/paulo/ex34.py b/modulo-01/paulo/ex34.py new file mode 100644 index 0000000..d5dcc40 --- /dev/null +++ b/modulo-01/paulo/ex34.py @@ -0,0 +1,30 @@ +import json + +config_inicial = { + "app": {"nome": "MeuApp", "versao": "1.0.0"}, + "banco": {"host": "localhost", "porta": 5432}, + "email": {"smtp": "smtp.gmail.com", "ativo": True} +} +with open("config.json", "w", encoding="utf-8") as f: + json.dump(config_inicial, f, indent=4) + +def carregar_config(caminho: str) -> dict: + with open(caminho, "r", encoding="utf-8") as f: + return json.load(f) + +def obter_valor(config: dict, chave: str, padrao: any = None) -> any: + chaves = chave.split('.') + atual = config + for c in chaves: + if isinstance(atual, dict) and c in atual: + atual = atual[c] + else: + return padrao + return atual + +config_lida = carregar_config("config.json") +print("app.nome:", obter_valor(config_lida, "app.nome")) +print("app.versao:", obter_valor(config_lida, "app.versao")) +print("banco.porta:", obter_valor(config_lida, "banco.porta")) +print("email.ativo:", obter_valor(config_lida, "email.ativo")) +print("chave.falsa:", obter_valor(config_lida, "chave.falsa", "MeuPadrão")) diff --git a/modulo-01/paulo/ex35.py b/modulo-01/paulo/ex35.py new file mode 100644 index 0000000..3e0c226 --- /dev/null +++ b/modulo-01/paulo/ex35.py @@ -0,0 +1,29 @@ +import json + +vendas_json = """ +[ + {"mes": "Janeiro", "produto": "Notebook", "quantidade": 45, "valor_unit": 3200.00}, + {"mes": "Janeiro", "produto": "Mouse", "quantidade": 120, "valor_unit": 89.90}, + {"mes": "Fevereiro","produto": "Notebook", "quantidade": 38, "valor_unit": 3200.00}, + {"mes": "Fevereiro","produto": "Teclado", "quantidade": 75, "valor_unit": 149.90}, + {"mes": "Março", "produto": "Monitor", "quantidade": 30, "valor_unit": 1200.00}, + {"mes": "Março", "produto": "Mouse", "quantidade": 200,"valor_unit": 89.90} +] +""" +vendas = json.loads(vendas_json) + +def calcular_total_mes(vendas: list, mes: str) -> float: + return sum(item["quantidade"] * item["valor_unit"] for item in vendas if item["mes"] == mes) + +def produto_mais_vendido(vendas: list) -> str: + quantidades = {} + for item in vendas: + quantidades[item["produto"]] = quantidades.get(item["produto"], 0) + item["quantidade"] + return max(quantidades, key=quantidades.get) if quantidades else "" + +def receita_total(vendas: list) -> float: + return sum(item["quantidade"] * item["valor_unit"] for item in vendas) + +print(f"Total Janeiro: R$ {calcular_total_mes(vendas, 'Janeiro'):.2f}") +print(f"Produto mais vendido: {produto_mais_vendido(vendas)}") +print(f"Receita Total: R$ {receita_total(vendas):.2f}") diff --git a/modulo-01/paulo/ex36.py b/modulo-01/paulo/ex36.py new file mode 100644 index 0000000..e6112ae --- /dev/null +++ b/modulo-01/paulo/ex36.py @@ -0,0 +1,51 @@ +import json +import os + +ARQUIVO = "contatos.json" + +def carregar_contatos() -> list: + if not os.path.exists(ARQUIVO): + return [] + with open(ARQUIVO, "r", encoding="utf-8") as f: + return json.load(f) + +def salvar_contatos(contatos: list) -> None: + with open(ARQUIVO, "w", encoding="utf-8") as f: + json.dump(contatos, f, indent=4) + +def adicionar_contato(nome: str, telefone: str, email: str) -> None: + contatos = carregar_contatos() + contatos.append({"nome": nome, "telefone": telefone, "email": email}) + salvar_contatos(contatos) + +def listar_contatos() -> list: + return carregar_contatos() + +def buscar_contato(nome: str) -> dict | None: + for contato in carregar_contatos(): + if contato["nome"].lower() == nome.lower(): + return contato + return None + +def remover_contato(nome: str) -> bool: + contatos = carregar_contatos() + for i, contato in enumerate(contatos): + if contato["nome"].lower() == nome.lower(): + del contatos[i] + salvar_contatos(contatos) + return True + return False + +# Limpa o arquivo para demonstração +if os.path.exists(ARQUIVO): + os.remove(ARQUIVO) + +# Demonstração +adicionar_contato("Ana", "11999999999", "ana@email.com") +adicionar_contato("Carlos", "11888888888", "carlos@email.com") +adicionar_contato("João", "11777777777", "joao@email.com") + +print("Contatos listados:", listar_contatos()) +print("Buscando Ana:", buscar_contato("Ana")) +print("Removendo Carlos:", remover_contato("Carlos")) +print("Contatos listados após remoção:", listar_contatos()) diff --git a/modulo-01/paulo/ex37.py b/modulo-01/paulo/ex37.py new file mode 100644 index 0000000..4b8876e --- /dev/null +++ b/modulo-01/paulo/ex37.py @@ -0,0 +1,42 @@ +import json +from datetime import datetime + +class Produto: + def __init__(self, nome: str, preco: float, criado_em: datetime = None): + self.nome = nome + self.preco = preco + self.criado_em = criado_em if criado_em else datetime.now() + +def produto_para_dict(produto: 'Produto') -> dict: + return { + "nome": produto.nome, + "preco": produto.preco, + "criado_em": produto.criado_em.isoformat() + } + +def dict_para_produto(dados: dict) -> 'Produto': + return Produto( + nome=dados["nome"], + preco=dados["preco"], + criado_em=datetime.fromisoformat(dados["criado_em"]) + ) + +produtos = [ + Produto("Mouse", 50.0), + Produto("Teclado", 150.0), + Produto("Monitor", 800.0) +] + +# Serialização +produtos_dict = [produto_para_dict(p) for p in produtos] +json_str = json.dumps(produtos_dict, indent=4) +print("JSON Serializado:") +print(json_str) + +# Desserialização +dados_lidos = json.loads(json_str) +produtos_desserializados = [dict_para_produto(d) for d in dados_lidos] + +print("\nProdutos Desserializados:") +for p in produtos_desserializados: + print(f"- {p.nome} (R$ {p.preco:.2f}) criado em {p.criado_em}") diff --git a/modulo-01/paulo/ex38.py b/modulo-01/paulo/ex38.py new file mode 100644 index 0000000..14f8649 --- /dev/null +++ b/modulo-01/paulo/ex38.py @@ -0,0 +1,29 @@ +from typing import TypeVar, List, Callable + +T = TypeVar('T') +R = TypeVar('R') + +def aplicar_transformacao(dados: List[T], funcao: Callable[[T], R]) -> List[R]: + """ + Aplica uma função de transformação a cada elemento de uma lista. + + Args: + dados (List[T]): Lista de dados de entrada. + funcao (Callable[[T], R]): Função de transformação. + + Returns: + List[R]: Lista com os elementos transformados. + """ + return [funcao(item) for item in dados] + +# 1. Lista de strings → maiúsculas +strings = ["ola", "mundo", "python"] +print("Strings maiúsculas:", aplicar_transformacao(strings, lambda s: s.upper())) + +# 2. Lista de floats → arredondados com 2 casas +floats = [3.14159, 2.71828, 1.61803] +print("Floats arredondados:", aplicar_transformacao(floats, lambda f: round(f, 2))) + +# 3. Lista de dicionários → extraindo um campo específico +dicts = [{"id": 1, "nome": "Ana"}, {"id": 2, "nome": "Carlos"}] +print("Nomes extraídos:", aplicar_transformacao(dicts, lambda d: d["nome"])) diff --git a/modulo-01/paulo/ex39.py b/modulo-01/paulo/ex39.py new file mode 100644 index 0000000..7a72c63 --- /dev/null +++ b/modulo-01/paulo/ex39.py @@ -0,0 +1,39 @@ +import json + +dados_brutos = [ + {"nome": " jOãO ", "email": "JOAO@TESTE.COM", "telefone": "11999998888"}, + {"nome": " aNa", "email": "ANA@TESTE.COM", "telefone": "11988887777"} +] + +with open("clientes_brutos.json", "w", encoding="utf-8") as f: + json.dump(dados_brutos, f) + +def carregar_dados(caminho: str) -> list[dict]: + with open(caminho, "r", encoding="utf-8") as f: + return json.load(f) + +def normalizar_dados(dados: list[dict]) -> list[dict]: + for cliente in dados: + cliente["nome"] = cliente["nome"].strip().title() + cliente["email"] = cliente["email"].strip().lower() + t = cliente["telefone"].strip() + if len(t) == 11: + cliente["telefone"] = f"({t[:2]}) {t[2:7]}-{t[7:]}" + return dados + +def enriquecer_dados(dados: list[dict]) -> list[dict]: + for cliente in dados: + cliente["status"] = "Ativo" + cliente["verificado"] = True + return dados + +def exportar_resultado(dados: list[dict], caminho: str) -> None: + with open(caminho, "w", encoding="utf-8") as f: + json.dump(dados, f, indent=4, ensure_ascii=False) + +dados_carregados = carregar_dados("clientes_brutos.json") +dados_normalizados = normalizar_dados(dados_carregados) +dados_enriquecidos = enriquecer_dados(dados_normalizados) +exportar_resultado(dados_enriquecidos, "clientes_processados.json") + +print("Pipeline executado. Verifique clientes_processados.json") diff --git a/modulo-01/paulo/ex40.py b/modulo-01/paulo/ex40.py new file mode 100644 index 0000000..e6cf976 --- /dev/null +++ b/modulo-01/paulo/ex40.py @@ -0,0 +1,123 @@ +import json +import os + +ARQUIVO_ALUNOS = "alunos.json" + +def _carregar_bd() -> list[dict]: + if not os.path.exists(ARQUIVO_ALUNOS): + return [] + with open(ARQUIVO_ALUNOS, "r", encoding="utf-8") as f: + return json.load(f) + +def _salvar_bd(dados: list[dict]) -> None: + with open(ARQUIVO_ALUNOS, "w", encoding="utf-8") as f: + json.dump(dados, f, indent=4, ensure_ascii=False) + +def cadastrar_aluno(nome: str, email: str, idade: int, notas: list[float]) -> dict: + """ + Cadastra um novo aluno no sistema. + + Args: + nome (str): O nome do aluno. + email (str): O e-mail do aluno. + idade (int): A idade do aluno. + notas (list[float]): A lista de notas do aluno. + + Returns: + dict: O dicionário do aluno recém-criado. + """ + alunos = _carregar_bd() + novo_id = max([a.get("id", 0) for a in alunos], default=0) + 1 + novo_aluno = { + "id": novo_id, + "nome": nome, + "email": email, + "idade": idade, + "notas": notas, + "ativo": True + } + alunos.append(novo_aluno) + _salvar_bd(alunos) + return novo_aluno + +def listar_alunos() -> list[dict]: + """ + Lista todos os alunos cadastrados. + + Returns: + list[dict]: A lista de todos os alunos. + """ + return _carregar_bd() + +def buscar_por_nome(nome: str) -> dict | None: + """ + Busca um aluno pelo nome. + + Args: + nome (str): O nome a ser buscado. + + Returns: + dict | None: Os dados do aluno ou None se não encontrado. + """ + for aluno in _carregar_bd(): + if aluno["nome"].lower() == nome.lower(): + return aluno + return None + +def calcular_media_turma() -> float: + """ + Calcula a média geral de todas as notas da turma. + + Returns: + float: A média da turma ou 0.0 se não houver notas. + """ + alunos = _carregar_bd() + todas_notas = [] + for a in alunos: + todas_notas.extend(a["notas"]) + + if not todas_notas: + return 0.0 + return sum(todas_notas) / len(todas_notas) + +def exportar_relatorio() -> None: + """ + Exporta um relatório da turma em formato JSON. + Inclui o total de alunos, média geral e os alunos com maior e menor média. + """ + alunos = _carregar_bd() + if not alunos: + print("Nenhum aluno para gerar relatório.") + return + + def media(aluno): + return sum(aluno["notas"]) / len(aluno["notas"]) if aluno["notas"] else 0.0 + + media_geral = calcular_media_turma() + aluno_maior = max(alunos, key=media) + aluno_menor = min(alunos, key=media) + + relatorio = { + "total_alunos": len(alunos), + "media_geral": round(media_geral, 2), + "maior_media": {"nome": aluno_maior["nome"], "media": round(media(aluno_maior), 2)}, + "menor_media": {"nome": aluno_menor["nome"], "media": round(media(aluno_menor), 2)} + } + + with open("relatorio_turma.json", "w", encoding="utf-8") as f: + json.dump(relatorio, f, indent=4, ensure_ascii=False) + +# Demonstração +if os.path.exists(ARQUIVO_ALUNOS): + os.remove(ARQUIVO_ALUNOS) + +cadastrar_aluno("Alice", "alice@email.com", 20, [8.0, 9.0, 10.0]) +cadastrar_aluno("Bruno", "bruno@email.com", 22, [5.0, 6.0, 5.5]) +cadastrar_aluno("Carla", "carla@email.com", 19, [9.5, 9.5, 9.0]) +cadastrar_aluno("Diego", "diego@email.com", 21, [7.0, 7.5, 8.0]) + +print("Total alunos listados:", len(listar_alunos())) +print("Buscando Carla:", buscar_por_nome("Carla")["nome"]) +print(f"Média da Turma: {calcular_media_turma():.2f}") +exportar_relatorio() +print("Relatório exportado para relatorio_turma.json") diff --git a/modulo-02/paulo/exercicios.py b/modulo-02/paulo/exercicios.py new file mode 100644 index 0000000..62b9792 --- /dev/null +++ b/modulo-02/paulo/exercicios.py @@ -0,0 +1,464 @@ +""" +============================================================= +MÓDULO 2 – Estruturas de Controle +Curso de Capacitação Full Stack – ITEAM + +Aluno(a): Paulo Roberto de Souza Mesquita Junior +Data : 20/05/2026 +============================================================= + +INSTRUÇÕES: + 1. Substitua e acima. + 2. Implemente cada função no espaço indicado com # SUA SOLUÇÃO AQUI. + 3. Não apague os comentários de orientação. + 4. Execute o arquivo para testar suas soluções antes de enviar. + 5. Suba este arquivo na pasta: + alunos//modulo-02/exercicios.py + +COMO EXECUTAR: + python exercicios.py +============================================================= +""" + + +# ============================================================== +# EXERCÍCIO 01 – Classificador de Temperatura +# Conceitos: if / elif / else, float(), input() +# ============================================================== +def ex01_classificador_temperatura(): + """ + Lê uma temperatura em Celsius e exibe sua classificação. + + Faixas: + < 0 → ❄️ Congelante + 0 a 14 → 🥶 Frio + 15 a 24 → 😊 Agradável + 25 a 34 → ☀️ Quente + >= 35 → 🔥 Muito quente + """ + # SUA SOLUÇÃO AQUI + temp = float(input("Digite a temperatura em Celsius: ")) + if temp < 0: + print("❄️ Congelante") + elif temp <= 14: + print("🥶 Frio") + elif temp <= 24: + print("😊 Agradável") + elif temp <= 34: + print("☀️ Quente") + else: + print("🔥 Muito quente") + + +# ============================================================== +# EXERCÍCIO 02 – Validador de Acesso +# Conceitos: if aninhado, comparação de strings +# ============================================================== +def ex02_validador_acesso(): + """ + Solicita usuário e senha e valida o acesso. + + Credenciais corretas: + usuário → "admin" + senha → "iteam2025" + """ + # SUA SOLUÇÃO AQUI + usuario = input("Digite o usuário: ") + senha = input("Digite a senha: ") + if usuario == "admin" and senha == "iteam2025": + print("Acesso concedido") + else: + print("Acesso negado") + + +# ============================================================== +# EXERCÍCIO 03 – Tabuada Interativa +# Conceitos: for, range(), f-string com alinhamento +# ============================================================== +def ex03_tabuada(): + """ + Solicita um número inteiro e exibe sua tabuada de 1 a 10. + """ + # SUA SOLUÇÃO AQUI + num = int(input("Digite um número para tabuada: ")) + for i in range(1, 11): + print(f"{num} x {i} = {num * i}") + + +# ============================================================== +# EXERCÍCIO 04 – Contador Regressivo +# Conceitos: while, print com end= +# ============================================================== +def ex04_contador_regressivo(): + """ + Solicita um número inteiro positivo e faz a contagem + regressiva até 0, finalizando com '🚀 Lançamento!'. + """ + # SUA SOLUÇÃO AQUI + num = int(input("Digite um número para contagem regressiva: ")) + while num > 0: + print(num, end=" ") + num -= 1 + print("🚀 Lançamento!") + + +# ============================================================== +# EXERCÍCIO 05 – Buscador com break +# Conceitos: for, break, enumerate() +# ============================================================== +def ex05_buscador_break(): + """ + Percorre o estoque e localiza 'Monitor', exibindo + sua posição. Usa break ao encontrar o item. + """ + estoque = ["Teclado", "Mouse", "Webcam", "Monitor", "Headset", "Notebook"] + + # SUA SOLUÇÃO AQUI + for i, item in enumerate(estoque): + if item == "Monitor": + print(f"Monitor encontrado na posição {i}") + break + + +# ============================================================== +# EXERCÍCIO 06 – Filtro de Dados com continue +# Conceitos: for, continue, None, acumuladores +# ============================================================== +def ex06_filtro_continue(): + """ + Percorre a lista de leituras, ignora os valores None + com continue e calcula soma, média e total ignorado. + """ + leituras = [12.5, None, 8.3, None, 15.0, 9.7, None, 11.2, 6.8, None] + soma = 0 + total = 0 + # SUA SOLUÇÃO AQUI + for leitura in leituras: + if leitura is None: + continue + soma += leitura + total += 1 + media = soma / total + print(f"Soma: {soma}") + print(f"Média: {media}") + print(f"Total ignorado: {total}") + + +# ============================================================== +# EXERCÍCIO 07 – Validação de Entrada com while +# Conceitos: while True, break, if/elif/else, float() +# ============================================================== +def ex07_validacao_nota(): + """ + Solicita a nota do aluno repetidamente até receber + um valor válido (0.0 a 10.0), então exibe o conceito. + + Conceitos: + 9.0 a 10.0 → A – Excelente + 7.0 a 8.9 → B – Bom + 5.0 a 6.9 → C – Regular + < 5.0 → D – Insuficiente + """ + # SUA SOLUÇÃO AQUI + while True: + nota = float(input("Digite a nota do aluno: ")) + if 0 <= nota <= 10: + break + if nota >= 9: + print("A – Excelente") + elif nota >= 7: + print("B – Bom") + elif nota >= 5: + print("C – Regular") + else: + print("D – Insuficiente") + + +# ============================================================== +# EXERCÍCIO 08 – Calculadora com try/except +# Conceitos: try/except/else/finally, ValueError, ZeroDivisionError +# ============================================================== +def ex08_calculadora_segura(): + """ + Solicita dois números e uma operação (+, -, *, /). + Trata: ValueError, ZeroDivisionError, operação inválida. + Usa else para exibir o resultado e finally para encerrar. + """ + # SUA SOLUÇÃO AQUI + try: + num1 = float(input("Digite o primeiro número: ")) + num2 = float(input("Digite o segundo número: ")) + operacao = input("Digite a operação (+, -, *, /): ") + if operacao == "+": + resultado = num1 + num2 + elif operacao == "-": + resultado = num1 - num2 + elif operacao == "*": + resultado = num1 * num2 + elif operacao == "/": + resultado = num1 / num2 + else: + print("Operação inválida") + except ValueError: + print("Valor inválido") + except ZeroDivisionError: + print("Divisão por zero") + else: + print("Resultado: ", resultado) + finally: + print("Fim do programa") + + +# ============================================================== +# EXERCÍCIO 09 – Padrão Numérico com for aninhado +# Conceitos: for aninhado, range(), print com end= +# ============================================================== +def ex09_padrao_numerico(): + """ + Gera o triângulo crescente: + 1 + 1 2 + 1 2 3 + ... + 1 2 3 4 5 + + Desafio extra: gera também o triângulo decrescente logo abaixo. + """ + # SUA SOLUÇÃO AQUI + for i in range(1, 6): + for j in range(1, i + 1): + print(j, end=" ") + print() + for i in range(4, 0, -1): + for j in range(1, i + 1): + print(j, end=" ") + print() + + +# ============================================================== +# EXERCÍCIO 10 – Jogo de Adivinhação +# Conceitos: while, contador, random, if/elif/else +# ============================================================== +def ex10_jogo_adivinhacao(): + """ + O computador sorteia um número entre 1 e 100. + O usuário tem 7 tentativas para adivinhar. + A cada erro, indica se o número é maior ou menor. + """ + import random + numero_secreto = random.randint(1, 100) + + # SUA SOLUÇÃO AQUI + for i in range(7): + num = int(input("Digite um número: ")) + if num == numero_secreto: + print("Parabéns! Você acertou!") + break + elif num < numero_secreto: + print("O número é maior") + else: + print("O número é menor") + + +# ============================================================== +# EXERCÍCIO 11 – Verificador de Número Primo +# Conceitos: for, break, try/except, otimização com √n +# ============================================================== +def ex11_numero_primo(): + """ + Solicita um número inteiro positivo e verifica se é primo. + Usa break ao encontrar o primeiro divisor. + Trata ValueError e números negativos/zero. + Otimização: verifica divisores somente até √n. + """ + # SUA SOLUÇÃO AQUI + import math + num = int(input("Digite um número: ")) + if num <= 1: + print("Não é primo") + else: + for i in range(2, int(math.sqrt(num)) + 1): + if num % i == 0: + print("Não é primo") + break + else: + print("É primo") + + +# ============================================================== +# EXERCÍCIO 12 – Analisador de Senha Forte +# Conceitos: for, if, booleanos, métodos de string +# ============================================================== +def ex12_analisador_senha(): + """ + Analisa se uma senha atende aos critérios de segurança: + - Mínimo 8 caracteres + - Pelo menos 1 maiúscula + - Pelo menos 1 minúscula + - Pelo menos 1 dígito + - Pelo menos 1 caractere especial: !@#$%^&* + + Exibe relatório com ✅ ou ❌ para cada critério. + """ + # SUA SOLUÇÃO AQUI + senha = input("Digite a senha: ") + if len(senha) < 8: + print("❌ Senha muito curta") + if not any(c.isupper() for c in senha): + print("❌ Senha sem letra maiúscula") + if not any(c.islower() for c in senha): + print("❌ Senha sem letra minúscula") + if not any(c.isdigit() for c in senha): + print("❌ Senha sem número") + if not any(c in "!@#$%^&*" for c in senha): + print("❌ Senha sem caractere especial") + else: + print("✅ Senha forte") + + +# ============================================================== +# EXERCÍCIO 13 – Simulador de Caixa Eletrônico +# Conceitos: while, //, if/else, try/except +# ============================================================== +def ex13_caixa_eletronico(): + """ + Solicita um valor de saque (múltiplo de R$10, máx R$3.000). + Calcula o menor número de cédulas: R$200, R$100, R$50, R$20, R$10. + Trata entradas inválidas. + """ + cedulas = [200, 100, 50, 20, 10] + + # SUA SOLUÇÃO AQUI + valor = int(input("Digite o valor do saque: ")) + if valor % 10 != 0: + print("O valor deve ser múltiplo de 10") + if valor > 3000: + print("O valor excede o limite de 3000") + for cedula in cedulas: + qtd = valor // cedula + if qtd > 0: + print(f"{qtd} cédulas de {cedula}") + valor %= cedula + + +# ============================================================== +# EXERCÍCIO 14 – Leitura de Múltiplos Dados com Tratamento +# Conceitos: while, break, continue, try/except, pass +# ============================================================== +def ex14_leitura_notas_turma(): + """ + Lê notas de uma turma até o usuário digitar 'fim'. + Ignora notas inválidas com continue + mensagem de aviso. + Ao encerrar, exibe: total, média, maior e menor nota. + """ + notas = [] + + # SUA SOLUÇÃO AQUI + while True: + nota = input("Digite a nota do aluno: ") + if nota == "fim": + break + try: + nota = float(nota) + if 0 <= nota <= 10: + notas.append(nota) + else: + print("Nota inválida") + except ValueError: + print("Valor inválido") + print(f"Total: {len(notas)}") + print(f"Média: {sum(notas) / len(notas)}") + print(f"Maior nota: {max(notas)}") + print(f"Menor nota: {min(notas)}") + + +# ============================================================== +# EXERCÍCIO 15 – Desafio Final: Menu de Sistema +# Conceitos: while True, if/elif/else, break, continue, try/except +# ============================================================== +def ex15_menu_sistema(): + """ + Menu interativo que permanece ativo até o usuário sair. + + Opções: + [1] Conversor de temperatura (Celsius → Fahrenheit) + [2] Verificador de número primo (versão simplificada) + [3] Analisador de senha (apenas comprimento e dígito) + [4] Calculadora segura (só +, -, *, /) + [0] Sair + + Usa try/except em toda entrada do usuário. + """ + while True: + print("\n" + "=" * 29) + print(" SISTEMA ITEAM - MENU ") + print("=" * 29) + print("[1] Conversor de temperatura") + print("[2] Verificador de número primo") + print("[3] Analisador de senha") + print("[4] Calculadora segura") + print("[0] Sair") + print("=" * 29) + + # SUA SOLUÇÃO AQUI — leia a opção e implemente cada funcionalidade + opcao = input("Digite a opção: ") + if opcao == "1": + ex01_classificador_temperatura() + elif opcao == "2": + ex02_validador_acesso() + elif opcao == "3": + ex03_tabuada() + elif opcao == "4": + ex04_contador_regressivo() + elif opcao == "5": + ex05_buscador_break() + elif opcao == "6": + ex06_filtro_continue() + elif opcao == "7": + ex07_validacao_nota() + elif opcao == "8": + ex08_calculadora_segura() + elif opcao == "9": + ex09_padrao_numerico() + elif opcao == "10": + ex10_jogo_adivinhacao() + elif opcao == "11": + ex11_numero_primo() + elif opcao == "12": + ex12_analisador_senha() + elif opcao == "13": + ex13_caixa_eletronico() + elif opcao == "14": + ex14_leitura_notas_turma() + elif opcao == "0": + break + else: + print("Opção inválida") + + +# ============================================================== +# EXECUÇÃO PRINCIPAL +# Descomente as chamadas dos exercícios que você já resolveu. +# ============================================================== +if __name__ == "__main__": + print("\n" + "=" * 50) + print("MÓDULO 2 – Estruturas de Controle") + print(f"Aluno(a): Paulo Mesquita") + print("=" * 50) + + # Descomente linha por linha conforme for resolvendo: + ex01_classificador_temperatura() + ex02_validador_acesso() + ex03_tabuada() + ex04_contador_regressivo() + ex05_buscador_break() + ex06_filtro_continue() + ex07_validacao_nota() + ex08_calculadora_segura() + ex09_padrao_numerico() + ex10_jogo_adivinhacao() + ex11_numero_primo() + ex12_analisador_senha() + ex13_caixa_eletronico() + ex14_leitura_notas_turma() + ex15_menu_sistema() diff --git a/projeto-01/Paulo/registry_atividades_paulo.py b/projeto-01/Paulo/registry_atividades_paulo.py new file mode 100644 index 0000000..724447f --- /dev/null +++ b/projeto-01/Paulo/registry_atividades_paulo.py @@ -0,0 +1,763 @@ +""" +============================================================= +ATIVIDADES — Registry Pattern em Python +Do fácil ao difícil: 5 desafios em contextos reais + +Curso de Capacitação Full Stack – ITEAM +Professor: Msc. Hygo Sousa De Oliveira + +Aluno: Paulo Mesquita +============================================================= + +INSTRUÇÕES GERAIS: + 1. Leia o código "ANTES" de cada atividade com atenção. + 2. Implemente a solução com Registry na seção indicada. + 3. O comportamento de saída deve ser IDÊNTICO ao original. + 4. Não apague o código "ANTES" — ele serve de referência. + 5. Execute e confira: os prints devem ser os mesmos. + +NÍVEIS: + 🟢 Atividade 1 — Básico (dicionário simples) + 🟢 Atividade 2 — Básico+ (classe Registry) + 🟡 Atividade 3 — Intermediário (decorator + classe) + 🟡 Atividade 4 — Intermediário (Decision Engine) + 🔴 Atividade 5 — Avançado (Registry completo + plugins) +============================================================= +""" + + +# ============================================================== +# 🟢 ATIVIDADE 1 — Calculadora de Operações +# Nível: Básico | Conceito: dicionário simples como registry +# ============================================================== + +print("=" * 60) +print("ATIVIDADE 1 — Calculadora de Operações") +print("=" * 60) + +# ── ANTES (if/elif) ────────────────────────────────────────── +def calcular_antes(operacao: str, a: float, b: float) -> float: + """Calculadora com if/elif — para ser refatorada.""" + if operacao == "soma": + return a + b + elif operacao == "subtracao": + return a - b + elif operacao == "multiplicacao": + return a * b + elif operacao == "divisao": + if b == 0: + raise ZeroDivisionError("Divisão por zero.") + return a / b + elif operacao == "potencia": + return a ** b + elif operacao == "modulo": + return a % b + else: + raise ValueError(f"Operação desconhecida: {operacao}") + +print("\n[ANTES]") +print(calcular_antes("soma", 10, 3)) # → 13 +print(calcular_antes("subtracao", 10, 3)) # → 7 +print(calcular_antes("multiplicacao", 10, 3)) # → 30 +print(calcular_antes("divisao", 10, 4)) # → 2.5 +print(calcular_antes("potencia", 2, 8)) # → 256.0 +print(calcular_antes("modulo", 10, 3)) # → 1 + + +# ── DEPOIS (Registry) ──────────────────────────────────────── +""" +TAREFA: + 1. Crie um dicionário OPERACOES_REGISTRY mapeando + nome → função (use lambdas ou funções nomeadas). + 2. Implemente calcular_depois() consultando o dicionário. + 3. Mantenha o tratamento de ZeroDivisionError e ValueError. + 4. Adicione uma operação nova: "raiz" (√a) sem tocar em + calcular_depois() — só adicionando no dicionário. + +DICA: + import math + OPERACOES_REGISTRY = { + "soma": lambda a, b: a + b, + ... + } +""" + +# SUA SOLUÇÃO AQUI ↓↓↓ +import math + +def _divisao(a: float, b: float) -> float: + if b == 0: + raise ZeroDivisionError("Divisão por zero.") + return a / b + +OPERACOES_REGISTRY: dict = { + "soma": lambda a, b: a + b, + "subtracao": lambda a, b: a - b, + "multiplicacao": lambda a, b: a * b, + "divisao": _divisao, + "potencia": lambda a, b: a ** b, + "modulo": lambda a, b: a % b, + "raiz": lambda a, b: math.sqrt(a) +} + +def calcular_depois(operacao: str, a: float, b: float) -> float: + if operacao not in OPERACOES_REGISTRY: + raise ValueError(f"Operação desconhecida: {operacao}") + return OPERACOES_REGISTRY[operacao](a, b) + +print("\n[DEPOIS]") +print(calcular_depois("soma", 10, 3)) +print(calcular_depois("subtracao", 10, 3)) +print(calcular_depois("multiplicacao", 10, 3)) +print(calcular_depois("divisao", 10, 4)) +print(calcular_depois("potencia", 2, 8)) +print(calcular_depois("modulo", 10, 3)) +print(calcular_depois("raiz", 16, 0)) # nova operação! + + +# ============================================================== +# 🟢 ATIVIDADE 2 — Sistema de Relatórios +# Nível: Básico+ | Conceito: classe Registry reutilizável +# ============================================================== + +print("\n" + "=" * 60) +print("ATIVIDADE 2 — Sistema de Relatórios") +print("=" * 60) + +# ── ANTES (if/elif) ────────────────────────────────────────── +def gerar_relatorio_antes(formato: str, dados: dict) -> None: + """Gerador de relatórios com if/elif — para ser refatorado.""" + if formato == "resumo": + print(f"[RESUMO] Total de itens: {len(dados)}") + for k, v in dados.items(): + print(f" {k}: {v}") + + elif formato == "detalhado": + print("[DETALHADO] ─────────────────") + for k, v in dados.items(): + tipo = type(v).__name__ + print(f" {k:15} | {str(v):20} | tipo: {tipo}") + print("─────────────────────────────") + + elif formato == "contagem": + print(f"[CONTAGEM] {len(dados)} campo(s) registrado(s).") + + elif formato == "chaves": + print(f"[CHAVES] {list(dados.keys())}") + + elif formato == "valores": + print(f"[VALORES] {list(dados.values())}") + + else: + raise ValueError(f"Formato desconhecido: {formato}") + + +dados_exemplo = {"nome": "Ana", "idade": 28, "cargo": "Dev", "salario": 9000.0} + +print("\n[ANTES]") +gerar_relatorio_antes("resumo", dados_exemplo) +gerar_relatorio_antes("contagem", dados_exemplo) +gerar_relatorio_antes("chaves", dados_exemplo) + + +# ── DEPOIS (Registry com classe) ───────────────────────────── +""" +TAREFA: + 1. Implemente (ou copie do material) a classe Registry. + 2. Crie uma instância: relatorio_registry = Registry() + 3. Extraia cada bloco do if/elif para uma função separada. + 4. Registre cada função no registry. + 5. Implemente gerar_relatorio_depois() sem nenhum if/elif. + 6. Adicione um formato novo "json_pretty" (usando json.dumps) + apenas adicionando-o ao registry — sem mudar a função principal. + +DICA: + class Registry: + def __init__(self): self._store = {} + def register(self, chave, valor): ... + def get(self, chave): ... + def __contains__(self, chave): ... +""" + +# SUA SOLUÇÃO AQUI ↓↓↓ +import json + +class Registry: + def __init__(self): + self._store = {} + + def register(self, chave: str, valor): + self._store[chave] = valor + + def get(self, chave: str): + if chave not in self._store: + raise ValueError(f"Formato desconhecido: {chave}") + return self._store[chave] + + def __contains__(self, chave: str): + return chave in self._store + +def _relatorio_resumo(dados: dict) -> None: + print(f"[RESUMO] Total de itens: {len(dados)}") + for k, v in dados.items(): + print(f" {k}: {v}") + +def _relatorio_detalhado(dados: dict) -> None: + print("[DETALHADO] ─────────────────") + for k, v in dados.items(): + tipo = type(v).__name__ + print(f" {k:15} | {str(v):20} | tipo: {tipo}") + print("─────────────────────────────") + +def _relatorio_contagem(dados: dict) -> None: + print(f"[CONTAGEM] {len(dados)} campo(s) registrado(s).") + +def _relatorio_chaves(dados: dict) -> None: + print(f"[CHAVES] {list(dados.keys())}") + +def _relatorio_valores(dados: dict) -> None: + print(f"[VALORES] {list(dados.values())}") + +def _relatorio_json_pretty(dados: dict) -> None: + print(f"[JSON] \n{json.dumps(dados, indent=4)}") + +relatorio_registry = Registry() +relatorio_registry.register("resumo", _relatorio_resumo) +relatorio_registry.register("detalhado", _relatorio_detalhado) +relatorio_registry.register("contagem", _relatorio_contagem) +relatorio_registry.register("chaves", _relatorio_chaves) +relatorio_registry.register("valores", _relatorio_valores) +relatorio_registry.register("json_pretty", _relatorio_json_pretty) + +def gerar_relatorio_depois(formato: str, dados: dict) -> None: + handler = relatorio_registry.get(formato) + handler(dados) + +print("\n[DEPOIS]") +gerar_relatorio_depois("resumo", dados_exemplo) +gerar_relatorio_depois("contagem", dados_exemplo) +gerar_relatorio_depois("chaves", dados_exemplo) +gerar_relatorio_depois("json_pretty", dados_exemplo) + + +# ============================================================== +# 🟡 ATIVIDADE 3 — Pipeline de Validação de Dados +# Nível: Intermediário | Conceito: decorator + Registry + chain +# ============================================================== + +print("\n" + "=" * 60) +print("ATIVIDADE 3 — Pipeline de Validação de Dados") +print("=" * 60) + +# ── ANTES (if/elif) ────────────────────────────────────────── +def validar_campo_antes(tipo: str, valor) -> tuple[bool, str]: + """ + Valida um valor conforme seu tipo. + Retorna (True, "") se válido, (False, mensagem) se inválido. + """ + if tipo == "email": + valido = "@" in str(valor) and "." in str(valor).split("@")[-1] + return (valido, "" if valido else "Email inválido: falta @ ou domínio") + + elif tipo == "cpf": + digitos = "".join(c for c in str(valor) if c.isdigit()) + valido = len(digitos) == 11 + return (valido, "" if valido else f"CPF inválido: esperado 11 dígitos, got {len(digitos)}") + + elif tipo == "telefone": + digitos = "".join(c for c in str(valor) if c.isdigit()) + valido = len(digitos) in (10, 11) + return (valido, "" if valido else "Telefone inválido: esperado 10 ou 11 dígitos") + + elif tipo == "cep": + digitos = "".join(c for c in str(valor) if c.isdigit()) + valido = len(digitos) == 8 + return (valido, "" if valido else "CEP inválido: esperado 8 dígitos") + + elif tipo == "idade": + try: + idade = int(valor) + valido = 0 <= idade <= 120 + return (valido, "" if valido else f"Idade inválida: {idade} fora de [0, 120]") + except (ValueError, TypeError): + return (False, f"Idade inválida: '{valor}' não é inteiro") + + elif tipo == "nome": + valido = isinstance(valor, str) and len(valor.strip()) >= 2 + return (valido, "" if valido else "Nome inválido: mínimo 2 caracteres") + + else: + return (False, f"Tipo de validação desconhecido: '{tipo}'") + + +print("\n[ANTES]") +casos = [ + ("email", "ana@iteam.com"), + ("email", "invalido_sem_arroba"), + ("cpf", "123.456.789-01"), + ("cpf", "123"), + ("telefone", "(92) 98765-4321"), + ("idade", 25), + ("idade", 200), + ("cep", "69000-000"), +] +for tipo, valor in casos: + ok, msg = validar_campo_antes(tipo, valor) + status = "✅" if ok else "❌" + print(f" {status} {tipo:10} | {str(valor):25} | {msg or 'OK'}") + + +# ── DEPOIS (Registry com decorator) ────────────────────────── +""" +TAREFA: + 1. Crie um Registry e um decorator @registrar_validador("tipo"). + 2. Cada validador vira uma função decorada: + + @registrar_validador("email") + def validar_email(valor) -> tuple[bool, str]: + ... + + 3. Implemente validar_campo_depois() sem if/elif. + 4. DESAFIO: adicione um validador "url" que verifica se o + valor começa com "http://" ou "https://" e contém "." + Apenas criando a função — sem tocar em validar_campo_depois(). + +DICA sobre o decorator: + validador_registry = Registry() + + def registrar_validador(tipo: str): + def decorator(func): + validador_registry.register(tipo, func) + return func + return decorator + + @registrar_validador("email") + def validar_email(valor) -> tuple[bool, str]: + ... +""" + +# SUA SOLUÇÃO AQUI ↓↓↓ +validador_registry = Registry() + +def registrar_validador(tipo: str): + def decorator(func): + validador_registry.register(tipo, func) + return func + return decorator + +@registrar_validador("email") +def validar_email(valor) -> tuple[bool, str]: + valido = "@" in str(valor) and "." in str(valor).split("@")[-1] + return (valido, "" if valido else "Email inválido: falta @ ou domínio") + +@registrar_validador("cpf") +def validar_cpf(valor) -> tuple[bool, str]: + digitos = "".join(c for c in str(valor) if c.isdigit()) + valido = len(digitos) == 11 + return (valido, "" if valido else f"CPF inválido: esperado 11 dígitos, got {len(digitos)}") + +@registrar_validador("telefone") +def validar_telefone(valor) -> tuple[bool, str]: + digitos = "".join(c for c in str(valor) if c.isdigit()) + valido = len(digitos) in (10, 11) + return (valido, "" if valido else "Telefone inválido: esperado 10 ou 11 dígitos") + +@registrar_validador("cep") +def validar_cep(valor) -> tuple[bool, str]: + digitos = "".join(c for c in str(valor) if c.isdigit()) + valido = len(digitos) == 8 + return (valido, "" if valido else "CEP inválido: esperado 8 dígitos") + +@registrar_validador("idade") +def validar_idade(valor) -> tuple[bool, str]: + try: + idade = int(valor) + valido = 0 <= idade <= 120 + return (valido, "" if valido else f"Idade inválida: {idade} fora de [0, 120]") + except (ValueError, TypeError): + return (False, f"Idade inválida: '{valor}' não é inteiro") + +@registrar_validador("nome") +def validar_nome(valor) -> tuple[bool, str]: + valido = isinstance(valor, str) and len(valor.strip()) >= 2 + return (valido, "" if valido else "Nome inválido: mínimo 2 caracteres") + +@registrar_validador("url") +def validar_url(valor) -> tuple[bool, str]: + valido = (str(valor).startswith("http://") or str(valor).startswith("https://")) and "." in str(valor) + return (valido, "" if valido else "URL inválida: deve começar com http:// ou https:// e conter '.'") + +def validar_campo_depois(tipo: str, valor) -> tuple[bool, str]: + if tipo not in validador_registry: + return (False, f"Tipo de validação desconhecido: '{tipo}'") + handler = validador_registry.get(tipo) + return handler(valor) + +print("\n[DEPOIS]") +for tipo, valor in casos: + ok, msg = validar_campo_depois(tipo, valor) + status = "✅" if ok else "❌" + print(f" {status} {tipo:10} | {str(valor):25} | {msg or 'OK'}") + +ok, msg = validar_campo_depois("url", "https://iteam.com") +status = "✅" if ok else "❌" +print(f" {status} {'url':10} | {'https://iteam.com':25} | {msg or 'OK'}") + + +# ============================================================== +# 🟡 ATIVIDADE 4 — Motor de Descontos de E-commerce +# Nível: Intermediário | Conceito: Decision Engine + Registry +# ============================================================== + +print("\n" + "=" * 60) +print("ATIVIDADE 4 — Motor de Descontos de E-commerce") +print("=" * 60) + +# ── ANTES (if/elif aninhado) ────────────────────────────────── +from dataclasses import dataclass as dc + +@dc +class Carrinho: + valor_total: float + cupom: str | None + tipo_cliente: str # "novo", "fiel", "vip" + dia_semana: int # 0=seg … 6=dom + quantidade_itens: int + + +def calcular_desconto_antes(carrinho: Carrinho) -> tuple[float, str]: + """ + Calcula o desconto e retorna (percentual, motivo). + Complexidade ciclomática alta — difícil de testar e manter. + """ + if carrinho.cupom == "BLACKFRIDAY": + return (0.30, "Cupom Black Friday: 30%") + + elif carrinho.cupom == "BEMVINDO10": + if carrinho.tipo_cliente != "novo": + return (0.0, "Cupom BEMVINDO10 apenas para novos clientes") + return (0.10, "Cupom de boas-vindas: 10%") + + elif carrinho.tipo_cliente == "vip": + if carrinho.valor_total >= 500: + return (0.20, "VIP + compra >= R$500: 20%") + return (0.10, "VIP: 10% base") + + elif carrinho.tipo_cliente == "fiel": + if carrinho.quantidade_itens >= 5: + return (0.15, "Fiel + 5 itens: 15%") + return (0.08, "Fiel: 8%") + + elif carrinho.dia_semana in (5, 6): # fim de semana + if carrinho.valor_total >= 200: + return (0.12, "FDS + >= R$200: 12%") + return (0.05, "Fim de semana: 5%") + + elif carrinho.valor_total >= 1000: + return (0.10, "Compra acima de R$1.000: 10%") + + return (0.0, "Sem desconto aplicável") + + +carrinhos_teste = [ + Carrinho(800.0, "BLACKFRIDAY", "normal", 2, 3), + Carrinho(150.0, "BEMVINDO10", "novo", 1, 1), + Carrinho(150.0, "BEMVINDO10", "fiel", 1, 2), + Carrinho(600.0, None, "vip", 2, 3), + Carrinho(100.0, None, "vip", 1, 0), + Carrinho(350.0, None, "fiel", 6, 4), + Carrinho(350.0, None, "fiel", 2, 4), + Carrinho(250.0, None, "normal", 6, 5), + Carrinho(80.0, None, "normal", 6, 6), + Carrinho(1200.0,None, "normal", 4, 1), + Carrinho(300.0, None, "normal", 2, 3), +] + +print("\n[ANTES]") +for c in carrinhos_teste: + pct, motivo = calcular_desconto_antes(c) + valor_desc = c.valor_total * pct + print(f" R$ {c.valor_total:7.2f} | {pct*100:4.0f}% | {motivo}") + + +# ── DEPOIS (Decision Engine + Registry) ────────────────────── +""" +TAREFA: + 1. Crie um Registry de handlers. Cada handler recebe + um Carrinho e retorna tuple[float, str]. + + 2. Crie a função decidir_regra(carrinho: Carrinho) -> str + — o Decision Engine. Ela contém TODA a lógica condicional + e retorna apenas uma chave simples como: + "cupom:blackfriday", "cliente:vip:alto", etc. + + 3. Registre um handler para cada chave. + + 4. Implemente calcular_desconto_depois() que: + chave = decidir_regra(carrinho) + handler = desconto_registry.get(chave) + return handler(carrinho) + + 5. DESAFIO: adicione uma nova regra "aniversario_loja" que + aplica 25% quando dia_semana == 3 (quarta-feira) e + valor_total >= 300. Adicione SEM tocar em calcular_desconto_depois(). + +ESTRUTURA SUGERIDA de chaves: + "cupom:blackfriday" + "cupom:bemvindo:valido" + "cupom:bemvindo:invalido" + "cliente:vip:alto_valor" + "cliente:vip:padrao" + "cliente:fiel:muitos_itens" + "cliente:fiel:padrao" + "fds:alto_valor" + "fds:padrao" + "compra:acima_mil" + "padrao" +""" + +# SUA SOLUÇÃO AQUI ↓↓↓ +desconto_registry = Registry() + +desconto_registry.register("cupom:blackfriday", lambda c: (0.30, "Cupom Black Friday: 30%")) +desconto_registry.register("cupom:bemvindo:invalido", lambda c: (0.0, "Cupom BEMVINDO10 apenas para novos clientes")) +desconto_registry.register("cupom:bemvindo:valido", lambda c: (0.10, "Cupom de boas-vindas: 10%")) +desconto_registry.register("cliente:vip:alto_valor", lambda c: (0.20, "VIP + compra >= R$500: 20%")) +desconto_registry.register("cliente:vip:padrao", lambda c: (0.10, "VIP: 10% base")) +desconto_registry.register("cliente:fiel:muitos_itens", lambda c: (0.15, "Fiel + 5 itens: 15%")) +desconto_registry.register("cliente:fiel:padrao", lambda c: (0.08, "Fiel: 8%")) +desconto_registry.register("fds:alto_valor", lambda c: (0.12, "FDS + >= R$200: 12%")) +desconto_registry.register("fds:padrao", lambda c: (0.05, "Fim de semana: 5%")) +desconto_registry.register("compra:acima_mil", lambda c: (0.10, "Compra acima de R$1.000: 10%")) +desconto_registry.register("padrao", lambda c: (0.0, "Sem desconto aplicável")) + +desconto_registry.register("promocao:aniversario_loja", lambda c: (0.25, "Aniversário da Loja: 25%")) + +def decidir_regra(carrinho: Carrinho) -> str: + if carrinho.cupom == "BLACKFRIDAY": + return "cupom:blackfriday" + + if carrinho.cupom == "BEMVINDO10": + if carrinho.tipo_cliente != "novo": + return "cupom:bemvindo:invalido" + return "cupom:bemvindo:valido" + + if carrinho.dia_semana == 3 and carrinho.valor_total >= 300: + return "promocao:aniversario_loja" + + if carrinho.tipo_cliente == "vip": + if carrinho.valor_total >= 500: + return "cliente:vip:alto_valor" + return "cliente:vip:padrao" + + if carrinho.tipo_cliente == "fiel": + if carrinho.quantidade_itens >= 5: + return "cliente:fiel:muitos_itens" + return "cliente:fiel:padrao" + + if carrinho.dia_semana in (5, 6): + if carrinho.valor_total >= 200: + return "fds:alto_valor" + return "fds:padrao" + + if carrinho.valor_total >= 1000: + return "compra:acima_mil" + + return "padrao" + +def calcular_desconto_depois(carrinho: Carrinho) -> tuple[float, str]: + chave = decidir_regra(carrinho) + handler = desconto_registry.get(chave) + return handler(carrinho) + +print("\n[DEPOIS]") +for c in carrinhos_teste: + pct, motivo = calcular_desconto_depois(c) + print(f" R$ {c.valor_total:7.2f} | {pct*100:4.0f}% | {motivo}") + +c_niver = Carrinho(350.0, None, "normal", 3, 2) +pct, motivo = calcular_desconto_depois(c_niver) +print(f" R$ {c_niver.valor_total:7.2f} | {pct*100:4.0f}% | {motivo} (TESTE NOVA REGRA)") + + +# ============================================================== +# 🔴 ATIVIDADE 5 — Sistema de Processamento de Eventos (Avançado) +# Nível: Avançado | Conceito: Registry completo + múltiplos registries +# + tratamento de erros + runtime update +# ============================================================== + +print("\n" + "=" * 60) +print("ATIVIDADE 5 — Sistema de Processamento de Eventos") +print("=" * 60) + +# ── ANTES (if/elif com lógica de negócio embutida) ─────────── +@dc +class Evento: + tipo: str + payload: dict + prioridade: int # 1=baixa, 2=média, 3=alta, 4=crítica + origem: str # "app", "api", "webhook", "cron" + + +def processar_evento_antes(evento: Evento) -> dict: + """ + Processador de eventos monolítico. + Mistura roteamento, lógica de negócio e formatação de resposta. + """ + resultado = {"evento": evento.tipo, "status": "ok", "acoes": []} + + if evento.tipo == "usuario.criado": + resultado["acoes"].append("email_boas_vindas enviado") + resultado["acoes"].append("perfil_inicial criado") + if evento.payload.get("plano") == "premium": + resultado["acoes"].append("acesso_premium liberado") + + elif evento.tipo == "usuario.deletado": + resultado["acoes"].append("dados_pessoais anonimizados") + resultado["acoes"].append("sessoes_ativas encerradas") + resultado["acoes"].append("log_auditoria registrado") + + elif evento.tipo == "pagamento.aprovado": + resultado["acoes"].append("pedido_liberado") + resultado["acoes"].append("nota_fiscal emitida") + if evento.prioridade >= 3: + resultado["acoes"].append("notificacao_prioritaria enviada") + + elif evento.tipo == "pagamento.recusado": + resultado["acoes"].append("cliente_notificado") + resultado["acoes"].append("retry_agendado para 1h") + if evento.payload.get("tentativas", 0) >= 3: + resultado["status"] = "bloqueado" + resultado["acoes"].append("conta_suspensa temporariamente") + + elif evento.tipo == "estoque.baixo": + resultado["acoes"].append("alerta_compras enviado") + produto = evento.payload.get("produto", "desconhecido") + qtd = evento.payload.get("quantidade", 0) + resultado["acoes"].append(f"reposicao_solicitada: {produto} ({qtd} un)") + + elif evento.tipo == "sistema.erro": + resultado["status"] = "erro" + resultado["acoes"].append("log_erro registrado") + if evento.prioridade == 4: + resultado["acoes"].append("oncall_acionado via PagerDuty") + resultado["acoes"].append("rollback_iniciado") + + else: + resultado["status"] = "ignorado" + resultado["acoes"].append(f"evento '{evento.tipo}' sem handler registrado") + + return resultado + + +eventos_teste = [ + Evento("usuario.criado", {"plano": "premium"}, 2, "api"), + Evento("usuario.criado", {"plano": "gratuito"}, 1, "app"), + Evento("usuario.deletado", {"motivo": "solicitação"},2, "app"), + Evento("pagamento.aprovado",{"valor": 1500.0}, 3, "webhook"), + Evento("pagamento.recusado",{"tentativas": 3}, 2, "api"), + Evento("estoque.baixo", {"produto": "Notebook", "quantidade": 2}, 3, "cron"), + Evento("sistema.erro", {"codigo": 500}, 4, "api"), + Evento("evento.desconhecido",{}, 1, "app"), +] + +print("\n[ANTES]") +for ev in eventos_teste: + res = processar_evento_antes(ev) + print(f" [{res['status'].upper():8}] {ev.tipo:25} → {res['acoes']}") + + +# ── DEPOIS (Registry Completo) ──────────────────────────────── +""" +TAREFA (leia com atenção — é o desafio mais completo): + +1. CLASSE REGISTRY COMPLETA + Implemente (ou use a do material) a classe Registry com: + - register(), get(), update(), unregister() + - __contains__(), listar_chaves() + - Tratamento de erros explícito + +2. HANDLERS ISOLADOS + Crie uma função handler para cada tipo de evento. + Cada handler recebe um Evento e retorna dict. + Extraia a lógica condicional interna para helpers ou + mantenha-a dentro do próprio handler. + +3. DECORATOR DE REGISTRO + Crie @registrar_evento("tipo") para auto-registrar + os handlers ao serem definidos. + +4. FUNÇÃO PRINCIPAL SEM if/elif + def processar_evento_depois(evento: Evento) -> dict: + try: + handler = evento_registry.get(evento.tipo) + except KeyError: + return {"evento": evento.tipo, "status": "ignorado", + "acoes": [f"sem handler para '{evento.tipo}'"]} + return handler(evento) + +5. RUNTIME UPDATE (feature flag simulado) + Após implementar tudo, simule uma atualização em runtime: + crie uma versão V2 do handler de "pagamento.aprovado" + que também envia o evento para um webhook externo, + e troque usando evento_registry.update(). Demonstre + que o comportamento muda sem reiniciar o programa. + +6. RELATÓRIO FINAL + Ao final, imprima os eventos registrados: + print(evento_registry.listar_chaves()) + +DICA DE ESTRUTURA: + evento_registry = Registry(nome="EventoRegistry") + + @registrar_evento("usuario.criado") + def handle_usuario_criado(evento: Evento) -> dict: + acoes = ["email_boas_vindas enviado", "perfil_inicial criado"] + if evento.payload.get("plano") == "premium": + acoes.append("acesso_premium liberado") + return {"evento": evento.tipo, "status": "ok", "acoes": acoes} + + # ... demais handlers ... + + def processar_evento_depois(evento: Evento) -> dict: + try: + handler = evento_registry.get(evento.tipo) + return handler(evento) + except KeyError: + return {"evento": evento.tipo, "status": "ignorado", + "acoes": [f"sem handler para '{evento.tipo}'"]} + + # Demonstração de runtime update: + @registrar_evento("pagamento.aprovado_v2") # define a v2 + def handle_pagamento_aprovado_v2(evento: Evento) -> dict: ... + + evento_registry.update("pagamento.aprovado", handle_pagamento_aprovado_v2) + print("\\n[FEATURE FLAG] handler de pagamento.aprovado atualizado em runtime!") +""" + +# SUA SOLUÇÃO AQUI ↓↓↓ + + +# ============================================================== +# CHECKLIST DE ENTREGA +# ============================================================== +print("\n" + "=" * 60) +print("CHECKLIST DE ENTREGA") +print("=" * 60) +print(""" +Para cada atividade, verifique: + + [ ] O comportamento de saída é idêntico ao bloco [ANTES] + [ ] A função principal NÃO contém nenhum if/elif de roteamento + [ ] Adicionar uma nova opção não exige modificar a função principal + [ ] Exceções são tratadas explicitamente (KeyError / ValueError) + [ ] O código está comentado e legível + +Atividade 1 — Calculadora [ ] Concluído +Atividade 2 — Relatórios [ ] Concluído +Atividade 3 — Validação (deco.) [ ] Concluído +Atividade 4 — Descontos (engine) [ ] Concluído +Atividade 5 — Eventos (completo) [ ] Concluído + +"Explicit is better than implicit." — Zen of Python +""")