Lección 8 de 12 · Nivel 2: Intermedio

Archivos, manejo de errores y proyecto final en Python

En esta lección
  1. Manejo de errores con try / except
  2. Leer y escribir archivos de texto
  3. Archivos CSV: datos en forma de tabla
  4. Archivos JSON: datos con estructura
  5. Proyecto del nivel intermedio: gestor de gastos personales
  6. Resumen
Lo que lograrás en esta lección
  • Manejar errores con try/except.
  • Leer y escribir archivos de texto, CSV y JSON.
  • Construir un gestor de gastos completo.
  • Cerrar el nivel intermedio con un proyecto real.
📥 Datos para practicar

Pon el archivo en la misma carpeta que tu programa para probar la lectura del CSV y el resumen por categoría.

  • gastos.csv · 40 gastos de ejemplo para el gestor de gastos

En esta lección, que cierra el nivel intermedio, tus programas dan el salto a lo útil de verdad: guardar y leer datos en archivos para no perder nada al cerrarlos, y manejar errores para que no se detengan cuando algo sale mal. Al final construirás un proyecto completo: un gestor de gastos personales que guarda la información en un archivo CSV que puedes abrir en Excel.

Manejo de errores con try / except

Cuando algo falla (el usuario escribe letras donde esperabas un número, un archivo no existe, divides entre cero), Python lanza una excepción y el programa se detiene. Con try/except la capturas y decides qué hacer:

try:
    edad = int(input("Edad: "))
    print(f"El año que viene tendrás {edad + 1}")
except ValueError:
    print("Eso no es un número entero")

Las excepciones más comunes

ExcepciónCuándo ocurre
ValueErrorConversión imposible: int("hola")
ZeroDivisionErrorDivisión entre cero
KeyErrorClave inexistente en un diccionario
IndexErrorPosición inexistente en una lista
FileNotFoundErrorEl archivo no existe
TypeErrorOperación con tipos incompatibles: "5" + 3

Estructura completa

try:
    a = float(input("Dividendo: "))
    b = float(input("Divisor: "))
    resultado = a / b
except ValueError:
    print("Escribe números válidos")
except ZeroDivisionError:
    print("No se puede dividir entre cero")
else:
    print(f"Resultado: {resultado:.2f}")   # solo si no hubo error
finally:
    print("Operación terminada")           # siempre se ejecuta

Pedir un número hasta que sea válido

Una función que reutilizarás en casi todos tus programas:

def pedir_float(mensaje):
    while True:
        texto = input(mensaje).strip().replace(",", ".")
        try:
            return float(texto)
        except ValueError:
            print("Valor no válido, intenta de nuevo.")
No captures todo a ciegas

Evita except: o except Exception: sin más, porque esconden errores de programación que deberías ver. Captura las excepciones concretas que esperas.

1. ¿Qué excepción lanza int("hola")?

  • ValueError
  • TypeError
  • ZeroDivisionError

ValueError aparece cuando el tipo es correcto (un texto) pero su contenido no se puede convertir.

Leer y escribir archivos de texto

La forma correcta de trabajar con archivos es con with, que los cierra automáticamente aunque haya un error:

# Escribir (crea el archivo o lo sobrescribe)
with open("notas.txt", "w", encoding="utf-8") as f:
    f.write("Primera línea\n")
    f.write("Segunda línea\n")

# Añadir al final sin borrar lo anterior
with open("notas.txt", "a", encoding="utf-8") as f:
    f.write("Tercera línea\n")

# Leer línea por línea
with open("notas.txt", "r", encoding="utf-8") as f:
    for linea in f:
        print(linea.strip())
ModoSignificado
"r"Leer (por defecto). Error si no existe.
"w"Escribir. Crea el archivo o borra su contenido.
"a"Añadir al final.

Indica siempre encoding="utf-8": evita problemas con tildes y eñes, sobre todo en Windows.

2. Abres con modo "w" un archivo que ya existe. ¿Qué pasa?

  • Se añade el texto al final
  • Se borra su contenido y se escribe desde cero
  • Da un error

"w" sobrescribe; para añadir al final sin borrar, usa "a".

Archivos CSV: datos en forma de tabla

CSV es el formato universal para intercambiar tablas: lo abren Excel, Google Sheets y cualquier base de datos. Python trae el módulo csv:

import csv

gastos = [
    {"fecha": "2026-10-01", "categoria": "comida", "monto": 35.5},
    {"fecha": "2026-10-02", "categoria": "transporte", "monto": 12.0},
]

# Escribir
with open("gastos.csv", "w", newline="", encoding="utf-8") as f:
    escritor = csv.DictWriter(f, fieldnames=["fecha", "categoria", "monto"])
    escritor.writeheader()
    escritor.writerows(gastos)

# Leer
with open("gastos.csv", newline="", encoding="utf-8") as f:
    for fila in csv.DictReader(f):
        print(fila["categoria"], float(fila["monto"]))

Al leer un CSV, todos los valores llegan como texto: convierte los números con float(). Si al abrir el archivo en Excel ves todo en una columna o las tildes raras, usa Datos → Desde texto/CSV y elige UTF-8 y coma como separador (o escribe el archivo con delimiter=";" y encoding="utf-8-sig" si tu Excel usa punto y coma).

Archivos JSON: datos con estructura

JSON guarda diccionarios y listas tal cual. Es el formato de las APIs web y de muchos archivos de configuración:

import json

agenda = {"Ana": "0991234567", "Luis": "0987654321"}

with open("agenda.json", "w", encoding="utf-8") as f:
    json.dump(agenda, f, ensure_ascii=False, indent=2)

with open("agenda.json", encoding="utf-8") as f:
    agenda = json.load(f)

Con esto puedes resolver el problema de la agenda de la lección 6: cárgala al iniciar y guárdala al salir.

3. Quieres guardar un diccionario con listas dentro y recuperarlo tal cual. ¿Qué usas?

  • Un CSV
  • json.dump() para guardar y json.load() para leer
  • print() con el diccionario

JSON conserva la estructura de diccionarios y listas; CSV es para tablas planas.

Proyecto del nivel intermedio: gestor de gastos personales

Este programa reúne todo el curso: variables, condicionales, bucles, diccionarios, funciones, archivos y manejo de errores. Permite registrar gastos, ver un resumen por categoría y los guarda en gastos.csv.

import csv
from datetime import date
from pathlib import Path

ARCHIVO = Path("gastos.csv")
CAMPOS = ["fecha", "categoria", "descripcion", "monto"]


def cargar_gastos():
    """Lee el CSV y devuelve una lista de diccionarios."""
    if not ARCHIVO.exists():
        return []
    with open(ARCHIVO, newline="", encoding="utf-8") as f:
        gastos = list(csv.DictReader(f))
    for g in gastos:
        g["monto"] = float(g["monto"])
    return gastos


def guardar_gasto(gasto):
    """Añade un gasto al final del CSV (crea el archivo si no existe)."""
    nuevo = not ARCHIVO.exists()
    with open(ARCHIVO, "a", newline="", encoding="utf-8") as f:
        escritor = csv.DictWriter(f, fieldnames=CAMPOS)
        if nuevo:
            escritor.writeheader()
        escritor.writerow(gasto)


def pedir_float(mensaje):
    while True:
        try:
            valor = float(input(mensaje).strip().replace(",", "."))
            if valor > 0:
                return valor
            print("El monto debe ser mayor que 0.")
        except ValueError:
            print("Escribe un número válido.")


def registrar():
    categoria = input("Categoría (comida, transporte, ocio...): ").strip().lower() or "otros"
    descripcion = input("Descripción: ").strip()
    monto = pedir_float("Monto: ")
    gasto = {"fecha": date.today().isoformat(), "categoria": categoria,
             "descripcion": descripcion, "monto": monto}
    guardar_gasto(gasto)
    print("✓ Gasto registrado")


def resumen(gastos):
    if not gastos:
        print("Todavía no hay gastos.")
        return
    total = sum(g["monto"] for g in gastos)
    por_categoria = {}
    for g in gastos:
        por_categoria[g["categoria"]] = por_categoria.get(g["categoria"], 0) + g["monto"]

    print(f"\n{'Categoría':15}{'Monto':>10}{'%':>8}")
    print("-" * 33)
    for cat, monto in sorted(por_categoria.items(), key=lambda x: x[1], reverse=True):
        print(f"{cat:15}{monto:10.2f}{monto / total:8.1%}")
    print("-" * 33)
    print(f"{'TOTAL':15}{total:10.2f}")
    mayor = max(gastos, key=lambda g: g["monto"])
    print(f"\nGasto más alto: {mayor['descripcion']} ({mayor['monto']:.2f})")


def main():
    while True:
        opcion = input("\n1) Registrar gasto  2) Ver resumen  3) Salir: ").strip()
        if opcion == "1":
            registrar()
        elif opcion == "2":
            resumen(cargar_gastos())
        elif opcion == "3":
            print("¡Hasta pronto!")
            break
        else:
            print("Opción no válida")


if __name__ == "__main__":
    main()

Lo que acabas de usar

  • pathlib.Path para comprobar si el archivo existe.
  • or "otros": si el usuario deja la categoría vacía, se usa un valor por defecto (el texto vacío es "falso").
  • Formato de columnas con f-strings: {cat:15} reserva 15 caracteres; {monto:>10} alinea a la derecha; {x:8.1%} muestra porcentaje.
  • sorted(..., key=..., reverse=True) para ordenar las categorías de mayor a menor gasto.

Retos para mejorar el proyecto

  1. Añade una opción para ver solo los gastos del mes actual (pista: compara g["fecha"][:7] con date.today().isoformat()[:7]).
  2. Define un presupuesto por categoría en un diccionario y avisa cuando una categoría lo supere.
  3. Agrega una opción para eliminar el último gasto registrado (tendrás que reescribir el archivo completo).
  4. Instala pandas (pip install pandas) y genera el resumen con pd.read_csv("gastos.csv").groupby("categoria")["monto"].sum().
Solución del reto 1
def gastos_del_mes(gastos):
    mes_actual = date.today().isoformat()[:7]   # "2026-10"
    return [g for g in gastos if g["fecha"][:7] == mes_actual]

# En el menú:
# elif opcion == "4":
#     resumen(gastos_del_mes(cargar_gastos()))

Resumen

  • try/except captura errores concretos; else y finally completan la estructura.
  • Abre archivos siempre con with y encoding="utf-8".
  • CSV para tablas (módulo csv), JSON para datos con estructura (módulo json).
  • El gestor de gastos combina todo lo que viste hasta ahora en un programa real.

¡Completaste el nivel intermedio! En la próxima lección empieza el nivel avanzado con la programación orientada a objetos: convertirás los diccionarios de tu gestor de gastos en clases.

¿Quieres tu certificado gratis?

Crea tu cuenta, marca tus avances y descarga el certificado al terminar el curso.

Inscribirme gratis