Construir el gestor de tareas

Ciencia y tecnologíaConstruir el gestor de tareas

En esta lección construirás una primera versión ejecutable del gestor. Podrá añadir, listar y completar tareas mientras permanezca abierto. Todavía no guardará en disco. Esta etapa intermedia permite comprobar la lógica y el menú antes de introducir rutas y archivos. Escribirás dos módulos completos y probarás un recorrido de uso real.

Crear el módulo de lógica

Crea una carpeta nueva llamada gestor-tareas. Dentro guarda logica.py con el código siguiente. Cada llamada a agregar_tarea crea un diccionario nuevo. La función devuelve False cuando el título no contiene información útil y True cuando lo añade.

def agregar_tarea(tareas, titulo):
    titulo = titulo.strip()
    if not titulo:
        return False
    tareas.append({"titulo": titulo, "hecha": False})
    return True


def completar_tarea(tareas, numero):
    if numero < 1 or numero > len(tareas):
        return False
    tareas[numero - 1]["hecha"] = True
    return True

La condición not titulo detecta una cadena vacía después de strip. No rechaza los espacios interiores de un título como «Leer una página». completar_tarea recibe un entero que representa el número visible. La conversión desde texto se hará en el menú antes de llamar a esta función.

Ambas funciones modifican la lista recibida. Su resultado booleano informa del éxito de la operación, no contiene una lista nueva. Por tanto no escribas tareas = agregar_tarea(…). Sustituirías la colección por True o False. Mantén separadas la modificación de datos y la comprobación del resultado devuelto.

Preparar el archivo principal

Crea app.py junto a logica.py y copia este archivo completo. No lo añadas debajo de otros ejemplos de menús: utiliza un archivo nuevo para evitar que se ejecuten dos programas seguidos. Las líneas vacías separan funciones y no afectan al comportamiento.

from logica import agregar_tarea, completar_tarea


def listar_tareas(tareas):
    if not tareas:
        print("No hay tareas")
        return
    for numero, tarea in enumerate(tareas, start=1):
        estado = "pendiente"
        if tarea["hecha"]:
            estado = "terminada"
        print(f"{numero}. {tarea['titulo']} ({estado})")


def solicitar_completado(tareas):
    listar_tareas(tareas)
    if not tareas:
        return
    try:
        numero = int(input("Número de tarea: "))
    except ValueError:
        print("Escribe un número entero")
        return
    if completar_tarea(tareas, numero):
        print("Tarea marcada como terminada")
    else:
        print("Ese número no aparece en la lista")


def main():
    tareas = []
    while True:
        print("1: añadir | 2: listar | 3: completar | 0: salir")
        opcion = input("Opción: ").strip()
        if opcion == "1":
            titulo = input("Título de la tarea: ")
            if agregar_tarea(tareas, titulo):
                print("Tarea añadida")
            else:
                print("El título no puede estar vacío")
        elif opcion == "2":
            listar_tareas(tareas)
        elif opcion == "3":
            solicitar_completado(tareas)
        elif opcion == "0":
            print("Fin de la sesión. Esta versión no guarda datos")
            break
        else:
            print("Opción no válida")


if __name__ == "__main__":
    main()

Ejecuta app.py desde su carpeta. Puedes utilizar py app.py o python3 app.py según el intérprete que comprobaste al preparar el entorno. Al elegir cero el bucle termina. Si vuelves a ejecutar la lista empieza vacía. El mensaje de salida lo explica para no crear una expectativa de guardado que todavía no existe.

Leer el flujo por responsabilidades

main conserva la lista y coordina las opciones. listar_tareas solo presenta los registros. solicitar_completado recoge un número, trata la conversión y llama a la lógica. Esta separación evita repetir el mismo bloque de listado en varios lugares y permite leer cada función con una pregunta concreta.

Los return de solicitar_completado terminan únicamente esa función. No cierran el programa entero. Cuando la función termina el control vuelve al menú que la llamó. Por eso una lista vacía o un número mal escrito producen un aviso y permiten continuar con otras acciones.

El break de la opción cero sí sale del bucle de main. Después main termina al no tener más instrucciones. Distinguir return y break te ayuda a seguir el recorrido: uno termina una función y el otro termina el bucle en el que se encuentra.

Hacer una primera demostración

Empieza eligiendo dos con la lista vacía. Debe aparecer «No hay tareas». Añade «Leer» y «Practicar». Vuelve a listar y comprueba que se numeran como uno y dos. Completa la primera y lista otra vez. Solo «Leer» debe aparecer terminada.

Intenta completar cero, tres y una palabra. Cero y tres están fuera de rango cuando hay dos tareas. La palabra falla durante la conversión a entero. Son rechazos por causas diferentes y los mensajes deben ayudarte a distinguirlos. Ninguno debería cambiar los estados existentes.

Añade un título compuesto solo por espacios. La longitud debe seguir siendo dos. Después añade otra tarea llamada «Leer». Ahora habrá tres registros y el nuevo comenzará pendiente. El programa permite títulos duplicados de acuerdo con el diseño de la lección anterior.

Mantener una versión que puedas explicar

No introduzcas guardado todavía aunque parezca fácil añadir una línea al salir. Primero confirma que cada operación en memoria funciona. Si mezclas al mismo tiempo errores de menú, de modelo y de archivo será más difícil localizar la causa. Conserva esta versión en una copia antes de pasar a la siguiente lección.

Tampoco necesitas cambiar el proyecto a una interfaz gráfica. Una terminal permite observar con claridad el intercambio de preguntas y respuestas. Lo que estás aprendiendo sobre datos, funciones y pruebas seguirá siendo útil cuando utilices otra presentación. La lógica no depende de botones para tener valor práctico.

Errores habituales

  • Guardar los dos módulos en carpetas diferentes sin ajustar las importaciones.
  • Asignar a tareas el booleano que devuelve agregar_tarea.
  • Restar uno al número antes de comprobar si es válido.
  • Esperar que la versión en memoria conserve tareas después de cerrarla.
  • Mezclar varios ejemplos completos dentro del mismo app.py.

Lo que deberías recordar

  • El menú coordina operaciones pero no necesita contener todas sus reglas.
  • Un rechazo no debería modificar los datos existentes.
  • return permite volver al menú desde una función auxiliar.
  • Esta versión conserva información solo mientras está en ejecución.

Ejercicio práctico

En la decimoctava hoja registra los dos archivos creados. Ejecuta la secuencia de lista vacía, dos altas, un completado y tres rechazos. Anota los títulos y estados que deben permanecer después de cada paso.

Sal con cero y vuelve a abrir. Comprueba que la agenda queda vacía y escribe por qué ese resultado es correcto en esta etapa. Conserva una copia de los archivos que funcionan. La siguiente lección añadirá persistencia sobre una base ya comprobada y sustituirá únicamente las partes indicadas del programa principal.

Siguiente capítulo: Añadir persistencia y revisar la aplicación.

Volver al índice del curso de programación desde cero.

Últimos posts

Artículos más vistos

Horóscopo diario
Menú diario