Archivos, errores y módulos
Python · Lección 4
La idea
Tres cosas que separan un script de notebook de código que otra persona puede correr: cerrar lo que abres, fallar con un mensaje útil, y poder importarse sin ejecutarse.
Archivos: siempre con with
with garantiza que el archivo se cierra aunque el bloque lance una excepción. Sin with, un error a media lectura deja el descriptor abierto; con miles de archivos, el proceso se queda sin descriptores y muere con un error que no dice nada.
encoding="utf-8" siempre
El encoding por defecto depende del sistema operativo. Tu código funcionará en tu Mac y fallará en el servidor de la empresa con UnicodeDecodeError en la primera tilde. Escríbelo explícito, siempre.
Leer línea por línea, sin cargar todo (Lección 3: el objeto archivo es un generador):
Para CSV real usa el módulo csv o pandas — manejan comas dentro de comillas, saltos de línea en campos y encodings raros. Lo de arriba es para entender qué hacen por dentro.
Rutas: pathlib, no concatenar strings
Path resuelve solo la diferencia entre / de macOS y \ de Windows. Concatenar strings con + o con os.path.join funciona, pero pathlib se lee mejor y trae .exists(), .mkdir(parents=True), .glob() y .read_text() incluidos.
Errores: capturar lo específico
except: pelado
try:
hacer_algo()
except: # ← captura TODO, incluido Ctrl-C y errores de memoria
pass # ← y lo tira a la basura en silencioEso convierte un bug en un misterio. Captura la excepción específica que sabes que puede ocurrir, y si de verdad necesitas capturar amplio, usa except Exception as e: y registra e.
Lanzar tus propios errores, con mensaje útil:
Un mensaje que incluye el valor que causó el problema te ahorra media hora de debugging. "trx inválido" no sirve; "trx debe ser positivo, recibí 0" sí.
Módulos y el guardián __main__
Cuando escribes mi_script.py y alguien hace import mi_script, todo el archivo se ejecuta. Si tenía código suelto al final, ese código corre en el import — casi nunca es lo que quieres.
__name__ vale "__main__" cuando el archivo se ejecuta directamente, y el nombre del módulo cuando se importa. Ese if es la línea que separa un script de una librería reutilizable — y es lo que vas a usar en cada archivo de scratch/.
Ejercicio 1 — Leer con manejo de error
Completa la función para que devuelva el contenido del archivo, o la cadena "no existe" si el archivo no está, sin dejar que la excepción se propague.
La excepción que lanza open() cuando el archivo no está es FileNotFoundError. Para leer, usa with open(ruta, encoding="utf-8") as f: return f.read().
Ejercicio 2 — Validar con raise
Escribe la validación: si alguna venta es negativa, lanza ValueError con un mensaje que incluya el valor ofensor.
La condición es v < 0. El mensaje debe contener el número: usa un f-string, por ejemplo f"venta negativa: {v}".
Reto
En proyectos/notebooks/F0-retos.ipynb:
- Escribe
cargar_ventas(ruta)que lea un CSV concsv.DictReader, conviertaventaafloatytrxaint, y lanceValueErrorcon el número de línea si alguna fila tiene datos inválidos. - Crea
scratch/io_utils.pycon esa función y su bloqueif __name__ == "__main__":de prueba. Impórtala desde un notebook y confirma que el bloque de prueba no corre. - Escribe un
context managerpropio concontextlib.contextmanagerque cronometre el bloque:with cronometro("carga"): ...debe imprimir cuánto tardó.
Para el Cerebro
Lee McKinney cap. 3 (archivos y excepciones) con estas preguntas escritas antes:
- ¿Qué diferencia hay entre abrir un archivo en modo
"w","a"y"x"? - ¿Qué es un context manager y qué dos métodos debe implementar?
- ¿Qué hace
elseen untry/except/else/finallyy cuándo sirve?
¿Qué garantiza `with` al abrir un archivo?::Que se cierra aunque el bloque lance una excepción
¿Por qué escribir encoding="utf-8" explícito?::El default depende del SO; sin él, el código rompe en otra máquina
¿Por qué nunca usar `except:` pelado?::Captura todo, incluido Ctrl-C, y esconde bugs
¿Qué debe incluir un buen mensaje de error?::El valor concreto que causó el problema
¿Qué vale __name__ al ejecutar un archivo directamente?::"__main__"; al importarlo vale el nombre del módulo
¿Por qué pathlib y no concatenar strings?::Resuelve separadores por SO y trae exists, mkdir, glob y read_text
Fuentes
Lo que esta página demuestra sola. Los ejercicios corren en tu navegador.
Lo que viene de los libros.
- Python for Data Analysis 3E (McKinney — libro abierto), §3 Built-In Data Structures, Functions, and Files
Índices verificados el 11-09-2026 contra el índice publicado de cada libro.
→ Siguiente: Entorno: uv, git y el repo