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.

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"])  # True

Lista 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 projeto

O 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.