Módulo 16 - Projeto final: seu gerenciador de tarefas
Adicionando e listando tarefas
10 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Definir o formato de uma tarefa: dicionário com texto e concluida.
- Implementar adicionar_tarefa com input e append.
- Implementar listar_tarefas com enumerate e marcador [x] ou [ ].
- Tratar a lista vazia com uma mensagem clara em vez de silêncio.
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: Adicionando e listando tarefas.
Os objetivos desta aula. Definir o formato de uma tarefa: dicionário com texto e concluida. Implementar adicionar_tarefa com input e append. Implementar listar_tarefas com enumerate e marcador [x] ou [ ]. Tratar a lista vazia com uma mensagem clara em vez de silêncio.
Veja o essencial, parte por parte.
A forma de uma tarefa. Cada tarefa é um dicionário com dois campos: "texto" (o que fazer) e "concluida" (True ou False).
Implementando adicionar_tarefa e listar_tarefas. for i, tarefa in enumerate(tarefas, start=1) significa: para cada tarefa da lista, me dê também o número dela, contando do 1.
Testando o que fizemos. Adicione uma tarefa com acento e cedilha, como Almoçar com a vovó, e liste: o Python 3 lida com acentos numa boa.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
A forma de uma tarefa
Antes de escrever as funções, uma decisão de projeto: qual é a cara de uma tarefa dentro do programa? Uma tarefa tem duas informações, o texto e o estado de concluída ou não. Poderíamos guardar só o texto numa lista de strings, mas aí o status não teria onde morar. A resposta certa é a do módulo 11: um dicionário, que junta as duas informações com nome em cada uma.
# A forma de UMA tarefa: um dicionário com dois campos
tarefa = {"texto": "Comprar pão", "concluida": False}
# A lista guarda várias tarefas, cada uma um dicionário
tarefas = [
{"texto": "Comprar pão", "concluida": False},
{"texto": "Pagar conta de luz", "concluida": True},
]
print(tarefas[1]["texto"]) # Pagar conta de luz
print(tarefas[1]["concluida"]) # TrueLista de dicionários: a lista dá a ordem, o dicionário dá o nome de cada campo. tarefas[1]["texto"] lê o texto da segunda tarefa.
Essa combinação de lista por fora e dicionário por dentro é uma das estruturas mais usadas na programação real. É assim que programas guardam listas de clientes, de produtos, de mensagens: uma coleção ordenada de registros, cada registro com campos nomeados. Dominar essa forma aqui, num projeto pequeno, é treinar o padrão que você vai rever em qualquer sistema de verdade.
Implementando adicionar_tarefa e listar_tarefas
Abra o seu gerenciador.py e substitua o corpo das duas funções, apagando os prints de em construção. Só essas duas mudam; todo o resto do esqueleto fica exatamente como está. Primeiro a mais curta:
def adicionar_tarefa(tarefas):
texto = input("Digite a tarefa: ")
tarefas.append({"texto": texto, "concluida": False})
print(f"Tarefa adicionada: {texto}")Três linhas de lógica: pede o texto, monta o dicionário com concluida=False e anexa na lista com append.
Toda tarefa nasce pendente, por isso o campo concluida entra fixo em False; mudar esse valor para True é trabalho da aula que vem. Note que a função altera a lista recebida por parâmetro com append, e essa alteração vale fora da função também: como o módulo 13 mostrou, a lista passada por parâmetro é a mesma lista, não uma cópia. É exatamente esse comportamento que faz o programa inteiro compartilhar as mesmas tarefas. Agora a listagem:
def listar_tarefas(tarefas):
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']}")listar_tarefas: mensagem para lista vazia, enumerate para numerar a partir do 1 e marcador de status antes do texto.
A primeira coisa que a função faz é tratar a lista vazia: mensagem clara e return, encerrando ali. Sem esse cuidado, escolher listar sem ter tarefas produziria uma tela em branco, e tela em branco parece programa travado. Depois vem o enumerate com start=1, que entrega posição e tarefa juntas a cada volta do for; começamos do 1 porque a numeração é para gente, e gente conta a partir do 1. Por fim, o if escolhe o marcador: [x] quando tarefa["concluida"] é True, [ ] quando é False, e a f-string do módulo 12 monta a linha final.
Testando o que fizemos
Rode o programa e faça o roteiro completo de teste: liste com a lista ainda vazia (opção 2), adicione duas tarefas (opção 1 duas vezes) e liste de novo. A sessão deve ficar assim:
Escolha uma opção: 2
Nenhuma tarefa na lista. Que tal adicionar a primeira?
Escolha uma opção: 1
Digite a tarefa: Comprar pão
Tarefa adicionada: Comprar pão
Escolha uma opção: 1
Digite a tarefa: Estudar a aula 4 do projeto
Tarefa adicionada: Estudar a aula 4 do projeto
Escolha uma opção: 2
1. [ ] Comprar pão
2. [ ] Estudar a aula 4 do projetoO roteiro de teste da aula: lista vazia tratada, duas adições e a listagem numerada com os marcadores de pendente.
As duas tarefas aparecem com [ ] porque nasceram pendentes, e nada ainda muda esse status: as opções 3 e 4 continuam respondendo em construção, como devem. Um detalhe importante do estágio atual: se você fechar o programa e abrir de novo, as tarefas somem. Elas vivem só na memória, numa lista que renasce vazia a cada execução. Isso não é defeito, é a aula 5 ainda não ter chegado; a gravação em arquivo é justamente o próximo grande passo depois de concluir e remover.
Teste rápido
Na função listar_tarefas, o que enumerate(tarefas, start=1) entrega a cada volta do for?
Perguntas frequentes
- Por que usar um dicionário por tarefa em vez de uma lista de textos simples?
- Porque a tarefa tem duas informações, texto e status, e a lista de strings só carrega uma. O dicionário dá nome a cada campo: tarefa["texto"] e tarefa["concluida"] se explicam sozinhos. E o formato aguenta crescer: se um dia você quiser prioridade ou data, é só adicionar mais um campo.
- Por que o campo concluida começa sempre em False?
- Porque tarefa recém-criada é, por definição, algo ainda não feito. Fixar False no nascimento garante o estado inicial correto sem perguntar nada ao usuário. Quem muda esse valor para True é a função concluir_tarefa, implementada na próxima aula.
- O que aconteceria se eu esquecesse o start=1 no enumerate?
- A numeração começaria do 0, padrão do Python, e a primeira tarefa apareceria como 0. Nada quebraria de imediato, mas na próxima aula o usuário vai digitar o número da tarefa para concluir ou remover, e a conta entre o número mostrado e a posição interna ficaria errada. Melhor alinhar desde já.
- Por que a listagem usa tarefa['texto'] com aspas simples dentro da f-string?
- Porque a f-string já está delimitada por aspas duplas, e repetir aspas duplas dentro dela encerraria a string no lugar errado. Alternar os dois tipos de aspas é o truque padrão: por fora duplas, por dentro simples, ou o contrário. O Python aceita as duas como equivalentes.
- Adicionei tarefas, fechei o programa e elas sumiram. Fiz algo errado?
- Não. Neste estágio as tarefas vivem só na memória, e memória se apaga quando o programa encerra. É o comportamento esperado até a aula 5, quando salvar_tarefas e carregar_tarefas passam a gravar e ler o arquivo tarefas.txt. Aí sim as tarefas sobrevivem entre sessões.
- Por que tratar a lista vazia com mensagem em vez de simplesmente não mostrar nada?
- Porque silêncio é a pior resposta que um programa pode dar: o usuário não sabe se a lista está vazia, se a opção falhou ou se o programa travou. Uma linha de mensagem elimina a dúvida e ainda convida à ação. Programas bons respondem sempre, mesmo quando não há nada a mostrar.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.