Do texto solto ao relatório: juntando tudo o que você aprendeu
Um bloco de texto com uma despesa por linha, do jeito que alguém realmente anotaria no dia a dia, e a missão de transformar essa bagunça num relatório organizado, por categoria, com totais certos.
Estudar esta lição interativa →Imagine que alguém te manda um bloco de texto assim, exatamente do jeito que uma pessoa real anotaria despesas no fim do dia, sem nenhuma formatação especial: "Mercado,Alimentação,150.30\nUber,Transporte,22.50\nCinema,Lazer,45.00\nPadaria,Alimentação,18.90", uma despesa por linha, separada por vírgulas. O trabalho deste projeto é transformar essa bagunça de texto solto num relatório organizado: total por categoria, e o total geral, formatado como algo que uma pessoa consiga realmente ler.
Esse é exatamente o tipo de problema onde Python brilha sem precisar de nenhuma página web, nenhum banco de dados: só texto entrando, análise (o "parsing") de cada linha, e um relatório saindo. Vamos construir isso passo a passo, reaproveitando praticamente todos os módulos deste curso: strings (Módulo 7), dicionários (Módulo 6), funções (Módulo 5), laços (Módulo 4) e tratamento de erros (Módulo 9), tudo junto num programa real.
texto = "Mercado,Alimentação,150.30\nUber,Transporte,22.50\nCinema,Lazer,45.00\nPadaria,Alimentação,18.90"
linhas = texto.strip().split("\n")
for linha in linhas:
campos = linha.split(",")
print(campos)Cada linha de texto vira uma lista de três campos: descrição, categoria e valor.
Primeiro passo: separar o texto em linhas (.strip().split("\n"), removendo espaços indesejados nas pontas), e depois cada linha em seus três campos (.split(",")). Repare que o valor, ao sair do split, ainda é texto ("150.30"), e precisa ser convertido para número com float(...) antes de qualquer conta, exatamente o tipo de conversão que você já viu no Módulo 2.
texto = "Mercado,Alimentação,150.30\nUber,Transporte,22.50\nCinema,Lazer,45.00\nPadaria,Alimentação,18.90"
totais_por_categoria = {}
linhas = texto.strip().split("\n")
for linha in linhas:
descricao, categoria, valor = linha.split(",")
totais_por_categoria[categoria] = totais_por_categoria.get(categoria, 0) + float(valor)
print(totais_por_categoria)Um dicionário acumula o total de cada categoria conforme as linhas são processadas.
Pense neste projeto como organizar um monte de recibos de papel jogados numa gaveta: primeiro você separa cada recibo individual (uma linha de texto por vez), depois lê o valor e a categoria de cada um, e por fim empilha os recibos em pilhas por categoria, somando cada pilha no final. O dicionário totais_por_categoria é exatamente essa pilha organizada, em forma de dados.
Com os totais calculados, a última etapa é formatar um relatório legível, usando f-strings e um laço sobre o dicionário de totais (.items(), do Módulo 6), fechando com o total geral (a soma de todos os valores). Nesta versão final, a leitura virou uma função e cada linha é processada dentro de um try/except ValueError (Módulo 9): as linhas ruins são anotadas e o relatório sai mesmo assim, avisando quais foram ignoradas:
texto = "Mercado,Alimentação,150.30\nUber,Transporte,22.50\nPadaria,Alimentação\nCinema,Lazer,quarenta\nCinema,Lazer,45.00\nPadaria,Alimentação,18.90"
def analisar(texto):
totais = {}
invalidas = [] # números das linhas que não deram para ler
for numero, linha in enumerate(texto.strip().split("\n"), start=1):
try:
descricao, categoria, valor = linha.split(",")
totais[categoria] = totais.get(categoria, 0) + float(valor)
except ValueError:
invalidas.append(numero) # faltou campo (linha 3) ou o valor não é número (linha 4)
return totais, invalidas
totais, invalidas = analisar(texto)
print("=== Relatório de despesas ===")
total_geral = 0
for categoria, total in totais.items():
print(f"{categoria}: R$ {total:.2f}")
total_geral = total_geral + total
print(f"Total geral: R$ {total_geral:.2f}")
if invalidas:
print("Linhas ignoradas por erro de formato:", invalidas)O relatório final combina f-strings, um laço sobre o dicionário e a soma total.
Se você também fez os cursos de HTML, CSS, JavaScript ou TypeScript desta plataforma, talvez tenha notado algo familiar aqui: aquele projeto contínuo evolui uma página de perfil através de cada curso, ganhando estrutura, estilo, comportamento e tipos. Este projeto de Python não mexe em nenhuma página, porque Python, sem um framework por cima, não tem DOM nem navegador para desenhar interface. Mas a lógica por trás é irmã gêmea da lógica de validação de formulário que talvez você já tenha escrito em JavaScript: analisar dados de entrada, aplicar regras, produzir um resultado organizado. Mesma cabeça, outra linguagem, outro tipo de saída (aqui, texto; lá, uma tela). E se você não fez nenhum dos outros cursos, sem problema nenhum: este projeto é completo e autocontido por si só.
Se uma linha do texto vier sem os três campos esperados (por exemplo, faltando o valor), o desempacotamento gera ValueError: not enough values to unpack (expected 3, got 2); se o valor não for um número, float("quarenta") gera ValueError: could not convert string to float. No exemplo, os dois casos caem no mesmo except ValueError, que anota o número da linha e deixa o laço seguir, em vez de derrubar o programa por causa de uma única linha ruim. Repare que o except nomeia o erro esperado (ValueError); um except: sem tipo esconderia também os bugs de verdade.
analisar_despesas(texto): para cada linha no formato "descrição,categoria,valor", acumule o valor (convertido para float, com ponto decimal, como 10.50) num dicionário totais por categoria, e devolva esse dicionário. Linhas vazias e linhas malformadas (que não tenham exatamente os três campos, ou cujo valor não seja um número) são ignoradas: não derrubam a função e não criam categoria. analisar_despesas("Mercado,Alimentação,100\nUber,Transporte,20\nPadaria,Alimentação,15") deve devolver um dicionário com "Alimentação": 115.0 e "Transporte": 20.0.def analisar_despesas(texto):
totais = {}
linhas = texto.strip().split("\n")
for linha in linhas:
if linha.strip() == "":
continue
# separe a linha em descricao, categoria, valor
# some o valor (convertido para float) em totais[categoria]
# linha malformada (faltou campo, ou o valor não é número): ignore e passe para a próxima
pass
return totais
🧩 Este é um exercício com correção automática — abra no app para completá-lo e verificar.
Uma última ponte, para quem fez os cursos de HTML, CSS e JavaScript: a página de perfil roda no navegador, mas os dados dela podem ser produzidos por Python. O módulo json transforma um dicionário (com listas e outros dicionários dentro) em texto JSON, o formato que uma página lê com fetch. O exemplo abaixo monta os dados de um perfil e os imprime nesse formato.
import json
perfil = {
"nome": "Ana Souza",
"habilidades": ["HTML semântico", "Acessibilidade web"],
"projetos": [{"titulo": "Blog de receitas", "link": "https://example.com/projeto2"}],
}
# Texto em formato JSON: o mesmo que uma página de perfil leria com fetch.
print(json.dumps(perfil, ensure_ascii=False, indent=2))Rode: o dicionário vira texto JSON, pronto para uma página ler.
Parabéns por chegar ao fim do curso de Python. Você saiu de um simples print("Olá, mundo!") até um programa que analisa texto solto, organiza dados por categoria e produz um relatório formatado, usando variáveis, decisões, laços, funções, coleções e tratamento de erros. As classes do Módulo 10 ficam como desafio: tente transformar cada despesa num objeto de uma classe Despesa. A partir daqui, o próximo passo natural é aplicar isso em problemas seus, reais, do seu próprio dia a dia: um script que organiza seus próprios gastos, uma automação de uma tarefa repetitiva, ou um mergulho mais fundo em alguma área específica, como dados ou automação web.