Python

Depuración: aprende a encontrar el error antes de culpar a Python

Aprende a depurar programas en Python de forma práctica. Reproduce errores, formula hipótesis, inspecciona variables, usa breakpoint() y encuentra la causa real antes de cambiar código.

Contenido de la guía
El problema

Python no mostró ningún error. El programa terminó normalmente. Y aun así, el resultado está mal.

Imagina una función muy sencilla: recibe varios precios y aplica un descuento del 10 %. Para una compra de 200 000, esperamos pagar 180 000. No parece haber demasiado misterio.

Esperábamos 180000
Python devuelve 199999.9
Lo extraño

No apareció un SyntaxError, ninguna excepción interrumpió la ejecución y tampoco tenemos un traceback que nos diga dónde mirar. Para Python, el programa terminó correctamente.

La pregunta

Si Python ni siquiera sabe que existe un problema, ¿cómo encontramos dónde nació el bug?

Python
def calcular_total(precios, descuento):
    subtotal = sum(precios)
    total = subtotal - descuento

    return total


precios = [120000, 80000]
descuento = 0.10

resultado = calcular_total(
    precios,
    descuento,
)

print(resultado)
Diagrama del proceso de depuración en Python
Depurar consiste en observar, formular hipótesis, aislar la causa, corregir y volver a comprobar.
Seguir la pista

El síntoma no siempre está donde vive el bug

Nosotros descubrimos el problema cuando aparece 199999.9 en pantalla. Es tentador mirar inmediatamente la línea que hizo el print(), pero esa línea solo está mostrando un valor que ya llegó equivocado.

Causa

Una operación produce un valor incorrecto.

Propagación

El programa continúa utilizando ese estado.

Síntoma

Finalmente observamos un resultado extraño.

!
Idea importante

La línea donde descubres un fallo y la línea donde nació pueden ser diferentes. Depurar significa seguir la pista hasta encontrar el primer punto donde el estado dejó de ser el esperado.

Reproducir

Antes de cambiar código, reproduce el problema

Cuando encontramos algo extraño, la primera reacción suele ser empezar a modificar líneas. Pero si cambiamos el programa antes de entender exactamente qué falla, podemos perder la mejor evidencia que tenemos.

Entrada precios = [120000, 80000]
descuento = 0.10
Esperado 180000
Obtenido 199999.9
Primera hipótesis

Quizá el valor de descuento no representa exactamente lo que nuestra función espera.

Hipótesis Medición Evidencia Conclusión
Regla práctica

Si puedes repetir el mismo fallo con las mismas entradas, ya tienes un experimento. Y si tienes un experimento, puedes comprobar si una hipótesis es correcta o incorrecta.

Texto plano
def calcular_total(precios, descuento):
    subtotal = sum(precios)

    print("subtotal:", subtotal)
    print("descuento:", descuento)

    total = subtotal - descuento

    print("total:", total)

    return total


precios = [120000, 80000]
descuento = 0.10

calcular_total(
    precios,
    descuento,
)
Observar

Inspeccionar no significa llenar el programa de prints

Los print() anteriores fueron útiles porque respondían preguntas concretas. El problema aparece cuando empezamos a imprimir todo lo que encontramos esperando que alguna línea nos revele mágicamente la respuesta.

print(x) ¿Qué valor tiene?

Permite observar directamente el contenido de una variable o expresión.

type(x) ¿Qué tipo es?

Ayuda a comprobar si estamos trabajando con el tipo de dato que realmente esperábamos.

repr(x) ¿Cómo se representa?

Muestra una representación útil para detectar detalles que una salida normal podría ocultar.

Lo que sabemos ahora

Nuestra hipótesis era que quizá el descuento tenía un valor distinto del esperado. La observación mostró descuento == 0.10. Eso nos obliga a cambiar la pregunta: quizá el valor está bien y el problema está en cómo lo utilizamos.

?
Antes de observar

No preguntes “¿qué puedo imprimir?”. Pregunta: “¿qué dato necesito observar para confirmar o descartar mi hipótesis?”

Texto plano
def calcular_total(precios, descuento):
    subtotal = sum(precios)

    breakpoint()

    total = subtotal - descuento

    return total


precios = [120000, 80000]
descuento = 0.10

resultado = calcular_total(
    precios,
    descuento,
)

print(resultado)
Detener

Qué mirar cuando detienes la ejecución

Al llegar a breakpoint(), Python pausa la ejecución y nos entrega una consola interactiva. El programa sigue vivo: simplemente está esperando que decidamos qué queremos observar o qué paso queremos ejecutar.

p Inspeccionar. Evalúa una variable o expresión.
n Siguiente. Ejecuta la siguiente línea.
s Entrar. Entra en una función llamada.
c Continuar. Reanuda la ejecución normal.
q Salir. Finaliza la sesión de depuración.
Ejecución normal
breakpoint()
Observar estado
Ejecutar un paso
Volver a observar
Nuestro próximo experimento

Detendremos la función justo después de calcular subtotal. Observaremos sus variables, ejecutaremos una operación y compararemos el estado antes y después.

Cambio de estado durante la depuración
Al avanzar una línea con el debugger, podemos comparar el estado antes y después y descubrir exactamente dónde aparece el valor incorrecto.
Aislar

Aísla el problema antes de corregirlo

Ya no estamos buscando el bug en todo el programa. Cada observación correcta reduce el número de lugares posibles donde puede estar escondido.

Entrada precios correctos
Subtotal 200000 ✓
Descuento 0.10 ✓
Sospecha subtotal - descuento
La búsqueda se hizo pequeña

Sabemos que subtotal vale 200000 y que descuento vale 0.10. El valor incorrecto aparece después de ejecutar subtotal - descuento.

Método

Una buena sesión de depuración convierte “algo está mal en mi programa” en una pregunta cada vez más pequeña, hasta que podemos señalar una operación concreta.

Estás viendo solo el 60% del contenido. Hazte Premium para acceder a la guía completa.

Comunidad

Comentarios y valoraciones

No hay comentarios aún. ¡Sé el primero en opinar!