En este capítulo, nos sumergimos en un proyecto práctico de Python: la creación de un gestor de tareas CLI (Command-Line Interface) en su versión inicial. Este proyecto integra conceptos fundamentales como listas, tuplas para datos inmutables, diccionarios para modelar estructuras clave-valor, sets para manejar etiquetas únicas, y operaciones de entrada/salida con archivos de texto (.txt) procesados línea por línea. Usaremos condicionales, bucles y comprehensions para construir lógica eficiente, todo sin recurrir a funciones avanzadas, programación orientada a objetos, decoradores o módulos externos. Imagina esto como construir un organizador personal desde cero, como un bloc de notas digital que vive en tu terminal, ayudándote a aplicar lo aprendido de manera tangible y a sentirte confiado en el manejo de datos básicos en Python.
Por Qué Este Proyecto Es Tu Próximo Paso en Python
Como mentor, te digo con exigencia: los proyectos no son solo ejercicios, son el puente entre teoría y maestría. Este gestor de tareas CLI te obliga a manipular datos reales de forma estructurada. Piensa en él como un asistente personal minimalista: agregarás tareas, las listarás, las marcarás como completadas y las guardarás en un archivo para persistencia. Usaremos listas para colecciones ordenadas de tareas, tuplas para representar cada tarea de manera inmutable (por ejemplo, (id, descripción, estado)), diccionarios para un modelo eficiente donde la clave es el ID y el valor son los detalles, y sets para etiquetas únicas sin duplicados. La E/S con archivos .txt se hará línea por línea, simulando una base de datos simple. No hay atajos aquí; cada paso se explica con profundidad para que lo domines, no solo lo copies.
Antes de codificar, asegúrate de tener Python instalado. Guardaremos el código en un archivo como gestor_tareas.py. Para ejecutarlo, abre tu terminal y escribe python gestor_tareas.py. Esto iniciará el programa en modo CLI, donde interactuarás mediante comandos de texto.
Diseñando la Estructura de Datos para Tareas
Comencemos por el núcleo: cómo representamos las tareas. Una tarea típica tiene un ID único, una descripción, un estado (pendiente o completada) y etiquetas. Usaremos un diccionario principal donde la clave es el ID (un entero) y el valor es una tupla inmutable con los detalles básicos: (descripción, estado). ¿Por qué tuplas? Son como contenedores sellados; una vez creadas, no se modifican accidentalmente, lo que es perfecto para datos fijos como una tarea inicial.
Para etiquetas, emplearemos sets porque garantizan unicidad – no quieres etiquetas duplicadas como “urgente” apareciendo dos veces. Imagina un set como una bolsa de etiquetas donde cada una es única, sin orden ni repeticiones.
Aquí va un ejemplo inicial de cómo inicializar estas estructuras. Copia esto en tu archivo gestor_tareas.py y ejecútalo con python gestor_tareas.py para ver la salida.
# Diccionario principal para tareas: {id: (descripcion, estado)}
tareas = {
1: ("Comprar leche", "pendiente"),
2: ("Llamar al doctor", "completada")
}
# Set para etiquetas de una tarea específica (por ejemplo, para ID 1)
etiquetas_tarea1 = {"urgente", "compras"}
# Imprimimos para verificar
print("Tareas:", tareas)
print("Etiquetas para tarea 1:", etiquetas_tarea1)
PythonEjecuta esto y verás cómo Python maneja estos datos de forma limpia. Nota los comentarios: cada línea explica su propósito. Ahora, expande tu comprensión: un diccionario es como un directorio telefónico (clave: nombre, valor: número), rápido para búsquedas. Un set es como una lista de invitados únicos a una fiesta – agrega uno y si ya existe, se ignora.
Implementando la Lógica Principal con Bucles y Condicionales
Ahora, construyamos el bucle principal del CLI. Usaremos un bucle while infinito que se rompe solo con un comando de salida. Dentro, leeremos inputs del usuario con input() y usaremos condicionales (if-elif-else) para manejar comandos como “agregar”, “listar”, “completar” o “salir”.
Para eficiencia, incorporaremos list comprehensions para generar listas derivadas, como filtrar tareas pendientes. Recuerda: una comprehension es como un atajo elegante para bucles – transforma datos en una sola línea, pero la explico paso a paso para que la domines.
Primero, explica el flujo: el programa carga tareas de un archivo .txt al inicio (lo cubriremos pronto), luego entra en el bucle CLI. Cada comando procesa los datos usando bucles for para iterar sobre diccionarios o lists.
Aquí un snippet del bucle principal. Agrega esto a tu archivo y ejecútalo.
# Diccionario de tareas (inicial vacío)
tareas = {}
# Bucle principal del CLI
while True:
comando = input("Ingrese comando (agregar, listar, completar, salir): ").strip().lower()
if comando == "salir":
break
elif comando == "listar":
if not tareas:
print("No hay tareas.")
else:
# Usamos list comprehension para formatear la salida
lista_tareas = [f"ID {id}: {desc} ({estado})" for id, (desc, estado) in tareas.items()]
for tarea in lista_tareas:
print(tarea)
elif comando == "agregar":
desc = input("Descripción: ")
id_nuevo = len(tareas) + 1 # ID secuencial
tareas[id_nuevo] = (desc, "pendiente") # Tupla inmutable
print(f"Tarea {id_nuevo} agregada.")
elif comando == "completar":
id_completar = int(input("ID a completar: "))
if id_completar in tareas:
desc, _ = tareas[id_completar] # Desempaquetamos tupla
tareas[id_completar] = (desc, "completada") # Nueva tupla
print(f"Tarea {id_completar} completada.")
else:
print("ID no encontrado.")
else:
print("Comando inválido.")
PythonObserva cómo usamos condicionales para ramificar la lógica. El bucle while mantiene el programa vivo hasta “salir”. La comprehension [f"ID {id}: {desc} ({estado})" for id, (desc, estado) in tareas.items()] es como decir: “Para cada ítem en el diccionario, crea una cadena formateada en una lista”. Es eficiente y legible – pruébalo agregando y listando tareas.
Manejo de Etiquetas con Sets
Las etiquetas añaden flexibilidad. Para cada tarea, asociamos un set de etiquetas en otro diccionario: {id: set_etiquetas}. Sets son ideales porque add() ignora duplicados automáticamente.
Imagina etiquetas como pegatinas en una nota: únicas y fáciles de agregar/quitar. Extiende el código anterior con esto.
# Diccionario para etiquetas: {id: set()}
etiquetas = {}
# En el comando "agregar", después de crear la tarea:
etiquetas[id_nuevo] = set() # Set vacío inicial
# Nuevo comando para agregar etiqueta
elif comando == "etiquetar":
id_tarea = int(input("ID de tarea: "))
if id_tarea in tareas:
etiqueta = input("Etiqueta: ")
if id_tarea not in etiquetas:
etiquetas[id_tarea] = set()
etiquetas[id_tarea].add(etiqueta) # Agrega al set, ignora duplicados
print(f"Etiqueta '{etiqueta}' agregada a tarea {id_tarea}.")
else:
print("ID no encontrado.")
# En "listar", modifica la comprehension para incluir etiquetas
lista_tareas = [
f"ID {id}: {desc} ({estado}) [Etiquetas: {', '.join(etiquetas.get(id, set()))}]"
for id, (desc, estado) in tareas.items()
]
PythonAquí, set() asegura unicidad. El método add() es como invitar a alguien a la fiesta solo si no está ya. Usa join() en una comprehension para mostrarlas – profundo pero accesible.
Persistencia con E/S en Archivos TXT Línea por Línea
Sin persistencia, las tareas se pierden al salir. Usaremos E/S con open() para leer/escribir en tareas.txt línea por línea. Cada línea será como “id|descripcion|estado|etiqueta1,etiqueta2”.
Al inicio, carga con un bucle for sobre el archivo. Al salir, guarda con otro bucle. Usa condicionales para manejar archivos vacíos.
Agrega esto al principio y al final.
# Cargar tareas desde archivo
tareas = {}
etiquetas = {}
try:
with open("tareas.txt", "r") as archivo:
for linea in archivo: # Línea por línea
partes = linea.strip().split("|")
if len(partes) >= 3:
id_tarea = int(partes[0])
desc = partes[1]
estado = partes[2]
tareas[id_tarea] = (desc, estado)
etiquetas[id_tarea] = set(partes[3].split(",")) if len(partes) > 3 else set()
except FileNotFoundError:
pass # Archivo no existe, empezar vacío
# Al final del bucle while, antes de break en "salir":
with open("tareas.txt", "w") as archivo:
for id_tarea, (desc, estado) in tareas.items():
etiq_str = ",".join(etiquetas.get(id_tarea, set()))
archivo.write(f"{id_tarea}|{desc}|{estado}|{etiq_str}\n") # Escribe línea por línea
PythonEsto usa bucles para procesar líneas, condicionales para errores, y comprehensions implícitas en splits. Como una libreta: lees página por página, escribes igual.
Optimizaciones con Comprehensions y Pruebas
Para pulir, usa comprehensions para filtrar, como tareas pendientes: pendientes = {id: data for id, data in tareas.items() if data[1] == "pendiente"}. Es como filtrar correos no leídos en una bandeja.
Prueba todo: agrega tareas, etiqueta, completa, lista y sal. Reinicia y verifica la persistencia. Si dominas esto, has internalizado estas estructuras – no solo las has visto.
Resumen del Capítulo
- Estructuras de datos integradas: Usamos listas para colecciones ordenadas, tuplas para tareas inmutables, diccionarios para modelado {id: datos}, y sets para etiquetas únicas sin duplicados.
- Lógica de control: Implementamos condicionales (if-elif-else) para comandos CLI, bucles (while y for) para iteraciones, y comprehensions para transformaciones eficientes de datos.
- Entrada/Salida con archivos: Cargamos y guardamos datos en .txt línea por línea usando
open(), manejando errores con try-except para robustez. - Funcionalidades del proyecto: Comandos para agregar tareas, listarlas con etiquetas, completarlas, etiquetarlas y salir, todo en un CLI interactivo.
- Mejores prácticas: Código comentado, legible y optimizado; explicaciones paso a paso con analogías para una comprensión profunda.
- Ejecución y pruebas: Guarda en
gestor_tareas.py, ejecuta conpython gestor_tareas.py, y experimenta para dominar el flujo.