IOKELU
Nivel: Intermedio – Proyecto 2
💡 Ejecuta el proyecto:
Guarda el archivo como notas.py y ejecútalo con:
python notas.py

Proyecto 2: Aplicación de notas con JSON y menú interactivo

En este proyecto crearás una aplicación de notas que permite añadir, listar, buscar y eliminar notas. Usarás JSON, funciones, manejo de archivos, excepciones y buenas prácticas.

Objetivos del proyecto

  • Practicar lectura y escritura de JSON.
  • Crear un menú interactivo profesional.
  • Organizar el código en funciones limpias.
  • Aplicar manejo de errores.

1. Estructura del proyecto

proyecto_notas/
    notas.py
    notas.json

2. Código completo de la aplicación

import json
import os

RUTA = "notas.json"


def cargar_notas():
    """Carga las notas desde el archivo JSON."""
    if not os.path.exists(RUTA):
        return []

    with open(RUTA, "r", encoding="utf-8") as archivo:
        try:
            return json.load(archivo)
        except json.JSONDecodeError:
            return []


def guardar_notas(notas):
    """Guarda las notas en el archivo JSON."""
    with open(RUTA, "w", encoding="utf-8") as archivo:
        json.dump(notas, archivo, indent=4, ensure_ascii=False)


def listar_notas(notas):
    """Muestra todas las notas."""
    if not notas:
        print("No hay notas.\n")
        return

    print("\n=== Lista de notas ===")
    for nota in notas:
        print(f'[{nota["id"]}] {nota["titulo"]}: {nota["contenido"]}')
    print()


def obtener_nuevo_id(notas):
    """Genera un ID incremental."""
    if not notas:
        return 1
    return max(n["id"] for n in notas) + 1


def agregar_nota(notas):
    """Añade una nueva nota."""
    titulo = input("Título: ").strip()
    contenido = input("Contenido: ").strip()

    if not titulo or not contenido:
        print("Título y contenido no pueden estar vacíos.\n")
        return

    nueva = {
        "id": obtener_nuevo_id(notas),
        "titulo": titulo,
        "contenido": contenido,
    }

    notas.append(nueva)
    guardar_notas(notas)
    print("Nota añadida.\n")


def buscar_nota(notas):
    """Busca notas por palabra clave."""
    clave = input("Buscar: ").strip().lower()

    resultados = [
        n for n in notas
        if clave in n["titulo"].lower() or clave in n["contenido"].lower()
    ]

    if not resultados:
        print("No se encontraron notas.\n")
        return

    print("\n=== Resultados ===")
    for n in resultados:
        print(f'[{n["id"]}] {n["titulo"]}: {n["contenido"]}')
    print()


def eliminar_nota(notas):
    """Elimina una nota por ID."""
    try:
        id_nota = int(input("ID a eliminar: "))
    except ValueError:
        print("ID inválido.\n")
        return

    nuevas = [n for n in notas if n["id"] != id_nota]

    if len(nuevas) == len(notas):
        print("No existe una nota con ese ID.\n")
        return

    guardar_notas(nuevas)
    print("Nota eliminada.\n")
    return nuevas


def menu():
    print("=== Aplicación de notas ===")
    print("1. Listar notas")
    print("2. Añadir nota")
    print("3. Buscar nota")
    print("4. Eliminar nota")
    print("5. Salir")


def main():
    notas = cargar_notas()

    while True:
        menu()
        opcion = input("Opción: ").strip()

        if opcion == "1":
            listar_notas(notas)
        elif opcion == "2":
            agregar_nota(notas)
        elif opcion == "3":
            buscar_nota(notas)
        elif opcion == "4":
            notas = eliminar_nota(notas) or notas
        elif opcion == "5":
            print("Saliendo...")
            break
        else:
            print("Opción inválida.\n")


if __name__ == "__main__":
    main()

3. Mejoras opcionales

4. Ejercicios del proyecto


Fin del nivel intermedio

Ya completaste todos los módulos y proyectos del nivel intermedio. Puedes continuar con el nivel avanzado cuando quieras.