Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Leer un Traceback (El Parte de Accidente)

Fig. 10.2: Un traceback se lee de abajo hacia arriba.

Atrapar errores con try es media historia. La otra media es saber leer el accidente cuando ocurre, porque muchísimos errores no se arreglan con un try: se arreglan entendiendo qué te está diciendo Python. Cuando algo falla, no se queda callado: imprime un traceback, un parte de accidente detallado. La mayoría de los principiantes lo ven, se asustan por el color rojo y lo ignoran, y se equivocan: ese texto te dice exactamente qué pasó y dónde.

Anatomía del Parte

Mira un traceback real:

Traceback (most recent call last):
  File "almacen.py", line 7, in <module>
    total = precio * cantidad
            ~~~~~~~^~~~~~~~~~
TypeError: can't multiply sequence by non-int of type 'str'

Se lee de abajo hacia arriba (ver Fig. 10.2), y la regla de oro es: la última línea es la que importa. Ahí está el tipo de error (TypeError) y el mensaje, siempre en inglés, de qué salió mal. Python no reporta en otro idioma, y en el trabajo profesional tampoco lo hará: conviene acostumbrarse a leerlo desde ahora. Este dice “can’t multiply sequence by non-int of type ‘str’”: no se puede multiplicar una secuencia (aquí, un texto) por algo que no sea un número entero. En otras palabras, intentaste texto * texto. Lo de arriba es el rastro de cómo llegó tu programa hasta el punto del choque.

Desde Python 3.11, además, esas rayitas señalan la expresión exacta que reventó, no solo la línea: las virgulillas (~) cubren los operandos y el ^ marca el operador que falló. Ya no tienes que adivinar cuál de tres operaciones en la misma línea falló: Python te lo subraya. Si tu terminal corre en el piso mínimo del libro (Python 3.10), no verás esta línea de marcas: el traceback se corta después del código y va directo al TypeError. Es lo esperado, no una señal de que algo está roto.

Los Accidentes Más Comunes

Estos cinco cubren la gran mayoría de lo que verás al empezar. Aprende a reconocerlos por su nombre:

El nombreQué significaCausa típica
NameErrorUsaste un nombre que no existeuna variable mal escrita o sin definir
TypeErrorMezclaste tipos incompatibles"50" * "2", sumar texto y número
IndexErrorPediste una posición que no existelista[10] en una lista de 3
KeyErrorPediste una clave que no existedic["edad"] sin esa clave
SyntaxError / IndentationErrorPython no pudo ni leer tu códigoun : que falta, una sangría torcida

Python te Sugiere la Solución

Las versiones modernas (Python 3.10 en adelante) hacen algo casi servicial: cuando te equivocas en un nombre por poco, te proponen el correcto.

NameError: name 'lndice' is not defined. Did you mean: 'indice'?

(“El nombre ‘lndice’ no está definido. ¿Quisiste decir: ‘indice’?”; Python 3.10+)

Y desde 3.12, si olvidaste importar un módulo de la biblioteca estándar, también te avisa:

NameError: name 'math' is not defined. Did you forget to import 'math'?

(“¿Olvidaste importar ‘math’?”; Python 3.12+)

Léelo como lo que es: una pista del propio intérprete. Antes de buscar en internet, lee la última línea completa. La mitad de las veces, la respuesta ya está ahí.

Acorralando al Bug

Leer el parte de accidente es la mitad del oficio. La otra mitad es cuando no hay accidente: el programa corre completo y entrega un resultado equivocado. Nada revienta, nada avisa, y aún así algo está mal. Para ese caso hay dos herramientas y una técnica.

El print táctico

El instinto de meter print por todos lados es correcto; lo que falla es la puntería. Un print táctico imprime el nombre y el valor juntos, en la frontera donde sospechas que el dato se corrompe:

total = calcular_total(carrito)
print(f"DEBUG total={total!r} tipo={type(total)}")   # ¿qué llegó de verdad?

Dos detalles de puntería: el !r muestra el valor crudo (con comillas, con espacios visibles: '50 ' en vez de 50, que es como se descubre el clásico espacio colado), y type() desenmascara al "50" que creías número. La técnica: pon el print DESPUÉS de la línea sospechosa, mira, y muévelo media función más arriba o abajo según lo que veas. Es una búsqueda dirigida, no una alfombra de prints regados por todo el código. Y cuando el bug muera, los prints de DEBUG se van: eran andamios temporales.

breakpoint(): congelar la escena

Cuando los prints no alcanzan, Python puede pausar el programa a mitad de ejecución. Escribe breakpoint() en la línea donde quieres detenerte y ejecuta normal:

def procesar(lote: list) -> int:
    total = 0
    for caja in lote:
        breakpoint()   # el programa se detiene AQUÍ, en cada vuelta
        total += caja
    return total

El programa se detiene ahí y te deja en una consola justo en ese punto, con todas las variables vivas a la mano. Cuatro comandos te bastan: p variable imprime cualquier variable, n avanza una línea, c continúa hasta el siguiente breakpoint, y q abandona. Cuando termines, borra la línea. (En la edición web esta pausa no funciona: es una herramienta de terminal.)

El método

Ni el print ni el breakpoint piensan por ti. La técnica que los vuelve útiles es vieja y confiable: formula una hipótesis antes de mirar. “Apuesto a que precio llega como texto.” Luego verifica. Si acertaste, ya sabes qué arreglar; si no, acabas de descartar una causa y la siguiente hipótesis es mejor. Sin hipótesis, mueves prints al azar esperando un milagro; con una, cada print te acerca a la falla.

Con esto, un traceback deja de ser un muro rojo y pasa a ser lo que de verdad es: la ruta más corta hacia el error. Ahora, a los ejercicios: provoca unos cuantos a propósito y practica leerlos.


Resumen del Capítulo

  • try/except intenta una operación riesgosa con un plan B listo; puedes encadenar varios except para distintos tipos de accidente.
  • Excepciones comunes: ValueError, TypeError, KeyError, FileNotFoundError, ZeroDivisionError; todas descienden de Exception.
  • except Tipo as e te da el mensaje exacto del error; finally ejecuta su bloque siempre, haya o no excepción.
  • raise ValueError("mensaje") lanza tu propia alerta cuando un dato viola las reglas del programa, en vez de dejar que falle más adelante.
  • Atrapa solo los errores previsibles que sabes manejar; nunca uses un except: a secas, que esconde hasta tus propios bugs.
  • Un traceback se lee de abajo hacia arriba: la última línea trae el tipo de error y su mensaje.
  • El print táctico (con !r y type()) y breakpoint() ayudan a acorralar un bug cuando el programa no truena, solo calcula mal.