Módulo 16 - Projeto final: seu gerenciador de tarefas
Polindo o programa: os toques finais
12 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Aplicar strip em todos os inputs para eliminar espaços acidentais.
- Recusar tarefa vazia e exigir confirmação s/n antes de remover.
- Adicionar o cabeçalho de abertura e a contagem de pendentes na saída.
- Conferir o seu programa contra o código final completo e comentado.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: Polindo o programa: os toques finais.
Os objetivos desta aula. Aplicar strip em todos os inputs para eliminar espaços acidentais. Recusar tarefa vazia e exigir confirmação s/n antes de remover. Adicionar o cabeçalho de abertura e a contagem de pendentes na saída. Conferir o seu programa contra o código final completo e comentado.
Veja o essencial, parte por parte.
Os cinco toques que fazem diferença. Cinco toques finais: cabeçalho de abertura, strip em todos os inputs, recusa de tarefa vazia, confirmação s/n antes de remover e contagem de pendentes na despedida.
Aplicando o polimento, mudança por mudança. O usuário pode responder S, s, ou até s com um espaço antes: todas significam sim para uma pessoa.
O código final completo. Chegou o momento de gala do curso: o programa inteiro, do primeiro comentário à última linha do loop, com todos os toques aplicados.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
Os cinco toques que fazem diferença
O gerenciador funciona, e isso já vale comemoração. Mas experimente usá-lo por uma semana e os incômodos aparecem: um espaço digitado sem querer antes da tarefa fica gravado para sempre, um Enter apressado cria uma tarefa fantasma vazia, um 4 digitado por engano apaga uma tarefa sem perguntar nada. Nenhum desses é um defeito de lógica; todos são falta de acabamento. Programas bons se diferenciam dos medianos exatamente aqui, nos detalhes que respeitam o usuário distraído.
| Toque | O problema que resolve | A ferramenta |
|---|---|---|
| Cabeçalho de abertura | O programa começa seco, sem identidade | print com moldura de sinais de igual |
| strip nos inputs | Espaços acidentais entram nos dados | input(...).strip() |
| Recusa de tarefa vazia | Enter apressado cria tarefa fantasma | if texto == "" com return |
| Confirmação s/n na remoção | Um número errado apaga sem dó | input de confirmação + lower() |
| Pendentes na despedida | A saída não informa nada útil | for com contador sobre a lista |
Os cinco toques da aula: cada um resolve um incômodo real de uso, com ferramentas que o curso já ensinou.
Repare na coluna de ferramentas: strip e lower são do módulo 12, o if com return você usou a aula inteira passada, e o contador com for é o módulo 9 puro. Polimento não é assunto avançado; é atitude. A pergunta que o separa do resto é simples: o que acontece se o usuário fizer a coisa errada aqui? Faça essa pergunta em cada input do seu programa e o acabamento se escreve sozinho.
Aplicando o polimento, mudança por mudança
Vamos às mudanças cirúrgicas. Em adicionar_tarefa, o strip entra grudado no input e o if barra o texto vazio antes do append. Toda entrada de dados do programa ganha o mesmo strip: as duas leituras de número (em concluir e remover) e a leitura da opção do menu.
def adicionar_tarefa(tarefas):
texto = input("Digite a tarefa: ").strip()
if texto == "":
print("Tarefa vazia não vale. Nada foi adicionado.")
return
tarefas.append({"texto": texto, "concluida": False})
print(f"Tarefa adicionada: {texto}")adicionar_tarefa polida: strip limpa as pontas e o if recusa o vazio antes que ele vire tarefa fantasma.
Em remover_tarefa, a confirmação entra depois da validação do número e antes do pop. O lower() aceita S maiúsculo e minúsculo como sim, e qualquer outra resposta cancela: na dúvida, não apague. Essa assimetria é proposital e é o padrão de todo software cuidadoso: a ação destrutiva exige um sim explícito; o cancelamento aceita qualquer coisa.
# dentro de remover_tarefa, após validar o número:
confirma = input(f"Remover '{tarefas[numero - 1]['texto']}'? (s/n): ").strip().lower()
if confirma != "s":
print("Remoção cancelada.")
return
removida = tarefas.pop(numero - 1)
print(f"Removida: {removida['texto']}")A confirmação mostra o texto da tarefa na pergunta, para a pessoa saber exatamente o que está prestes a apagar.
Faltam as pontas do programa: o cabeçalho na abertura, logo após o carregar_tarefas, e a despedida com a contagem de pendentes na opção 5. A contagem é um for com contador que soma 1 para cada tarefa cujo concluida é False. Sair do programa informando o que ficou por fazer transforma a despedida em lembrete útil.
O código final completo
Chegou o momento de gala do curso: o programa inteiro, do primeiro comentário à última linha do loop, com todos os toques aplicados. Use este código como gabarito de conferência do seu, não como fonte de cópia; se você construiu aula a aula, a diferença entre o seu arquivo e este deve ser mínima. Leia com orgulho: semanas atrás, você não sabia o que era uma variável.
# gerenciador.py - Gerenciador de tarefas
# Projeto final do curso de Python Básico do ValorFinal.
# Menu no terminal, tarefas em lista de dicionários, gravação em tarefas.txt.
ARQUIVO = "tarefas.txt"
def mostrar_menu():
# Mostra as opções a cada volta do loop principal.
print("\n=== MINHAS TAREFAS ===")
print("1. Adicionar tarefa")
print("2. Listar tarefas")
print("3. Concluir tarefa")
print("4. Remover tarefa")
print("5. Sair")
def adicionar_tarefa(tarefas):
# Pede o texto, recusa vazio e anexa o dicionário na lista.
texto = input("Digite a tarefa: ").strip()
if texto == "":
print("Tarefa vazia não vale. Nada foi adicionado.")
return
tarefas.append({"texto": texto, "concluida": False})
print(f"Tarefa adicionada: {texto}")
def listar_tarefas(tarefas):
# Numera a partir do 1 e marca [x] concluída, [ ] pendente.
if len(tarefas) == 0:
print("Nenhuma tarefa na lista. Que tal adicionar a primeira?")
return
for i, tarefa in enumerate(tarefas, start=1):
if tarefa["concluida"]:
marca = "[x]"
else:
marca = "[ ]"
print(f"{i}. {marca} {tarefa['texto']}")
def concluir_tarefa(tarefas):
# Escolhe por número, com conversão protegida e intervalo validado.
if len(tarefas) == 0:
print("Não há tarefas para concluir.")
return
listar_tarefas(tarefas)
resposta = input("Número da tarefa concluída: ").strip()
try:
numero = int(resposta)
except ValueError:
print("Digite apenas o número da tarefa.")
return
if numero < 1 or numero > len(tarefas):
print("Não existe tarefa com esse número.")
return
tarefas[numero - 1]["concluida"] = True
print("Tarefa marcada como concluída. Bom trabalho!")
def remover_tarefa(tarefas):
# Mesmo escudo de validação, mais a confirmação s/n antes do pop.
if len(tarefas) == 0:
print("Não há tarefas para remover.")
return
listar_tarefas(tarefas)
resposta = input("Número da tarefa a remover: ").strip()
try:
numero = int(resposta)
except ValueError:
print("Digite apenas o número da tarefa.")
return
if numero < 1 or numero > len(tarefas):
print("Não existe tarefa com esse número.")
return
confirma = input(f"Remover '{tarefas[numero - 1]['texto']}'? (s/n): ").strip().lower()
if confirma != "s":
print("Remoção cancelada.")
return
removida = tarefas.pop(numero - 1)
print(f"Removida: {removida['texto']}")
def salvar_tarefas(tarefas):
# Reescreve o arquivo inteiro: uma linha por tarefa, status;texto.
with open(ARQUIVO, "w", encoding="utf-8") as arquivo:
for tarefa in tarefas:
if tarefa["concluida"]:
status = "1"
else:
status = "0"
arquivo.write(status + ";" + tarefa["texto"] + "\n")
def carregar_tarefas():
# Reconstrói a lista a partir do arquivo; sem arquivo, começa vazia.
tarefas = []
try:
with open(ARQUIVO, "r", encoding="utf-8") as arquivo:
for linha in arquivo:
linha = linha.strip()
if linha == "":
continue
status, texto = linha.split(";", 1)
tarefas.append({"texto": texto, "concluida": status == "1"})
except FileNotFoundError:
pass
return tarefas
# Programa principal: carrega, apresenta e entra no loop do menu.
tarefas = carregar_tarefas()
print("=" * 26)
print(" MINHAS TAREFAS 1.0")
print("=" * 26)
while True:
mostrar_menu()
opcao = input("Escolha uma opção: ").strip()
if opcao == "1":
adicionar_tarefa(tarefas)
salvar_tarefas(tarefas)
elif opcao == "2":
listar_tarefas(tarefas)
elif opcao == "3":
concluir_tarefa(tarefas)
salvar_tarefas(tarefas)
elif opcao == "4":
remover_tarefa(tarefas)
salvar_tarefas(tarefas)
elif opcao == "5":
pendentes = 0
for tarefa in tarefas:
if not tarefa["concluida"]:
pendentes += 1
print(f"Até logo! Tarefas pendentes: {pendentes}")
break
else:
print("Opção inválida. Digite um número de 1 a 5.")O gerenciador de tarefas completo: 7 funções, validação em todas as entradas, persistência em arquivo e os toques de acabamento.
Rode a bateria final de testes: adicione uma tarefa com espaços nas pontas e confira que ficou limpa; tente adicionar uma vazia e veja a recusa; remova uma tarefa respondendo n na confirmação e confira que ela sobreviveu; saia com pendências e veja a contagem na despedida; feche e reabra o programa e confira que tudo voltou do arquivo. Passou em tudo? Então respire fundo: você escreveu, sozinho e entendendo cada linha, um programa completo em Python. A próxima aula fecha o curso olhando para trás e para frente.
Teste rápido
Na confirmação da remoção, por que qualquer resposta diferente de s cancela, em vez de exigir um n explícito para cancelar?
Perguntas frequentes
- Meu código ficou um pouco diferente do gabarito. Está errado?
- Não necessariamente. Mensagens com outras palavras, nomes de variáveis locais diferentes e espaçamentos distintos são variação normal. O que precisa bater é o comportamento: os cinco toques funcionando, as validações segurando entrada errada e o arquivo indo e voltando. Teste contra o roteiro da aula; passou, está certo.
- Por que o strip também entrou na leitura da opção do menu?
- Pelo mesmo motivo dos outros inputs: um espaço acidental transformaria "1 " numa opção diferente de "1", e o usuário cairia no aviso de opção inválida sem entender o porquê. Normalizar toda entrada assim que ela chega é um hábito barato que elimina uma família inteira de bugs de eu jurava que tinha digitado certo.
- O que faz exatamente o print("=" * 26) do cabeçalho?
- Multiplicar uma string por um número repete a string: "=" * 26 produz uma linha com 26 sinais de igual. É um truque do módulo 12 para desenhar molduras sem digitar caractere por caractere. Mude o número e a moldura estica ou encolhe junto.
- Por que contar as pendentes com um for em vez de contar as concluídas?
- Porque a informação útil na despedida é o que ainda falta, não o que já foi. O for percorre a lista e soma 1 sempre que concluida é False, usando o not para inverter o teste. Contar as concluídas daria um número verdadeiro, mas responderia a pergunta errada.
- O programa está pronto. Devo memorizar este código?
- Não. Memorize o desenho, não as linhas: um loop de menu, funções por ação, validação em toda entrada, gravação após toda mudança. Esses quatro princípios reconstroem este programa e servem de planta para dezenas de outros. Código se consulta; estrutura se carrega na cabeça.
- Posso publicar esse projeto no meu GitHub?
- Pode e é uma boa ideia, com a honestidade de sempre: descreva como projeto de estudo do curso de Python Básico. Melhor ainda se você adicionar alguma evolução sua depois, como as ideias da próxima aula; a diferença entre o gabarito e a sua versão é o que mostra a sua digital.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.