|
|
|
|
|
|
|
|
En un programa pueden producirse diferentes tipos de errores, y es útil saber distinguirlos para poder localizarlos más rápido.
El primer paso en la depuración es averiguar el tipo del error que se debe solucionar. Si bien las siguientes secciones se organizan según el tipo de error, algunas técnicas son aplicables a más de una situación.
Los errores de sintaxis suelen ser fáciles de solucionar una vez que se encuentran e identifican. Desgraciadamente, los mensajes de error a veces no son de gran ayuda. Los mensajes más comunes son SyntaxError: invalid syntax y SyntaxError: invalid token, pero ninguno de los dos es muy concreto.
No obstante, el mensaje informa del punto del programa en el que el se ha producido el problema. Mejor dicho, informa del lugar en el que Python se ha dado cuenta del problema, que no siempre coincide con la localización del error. A veces el error está antes del punto indicado en el mensaje, frecuentemente en la línea anterior.
Si has desarrollado el programa de forma incremental, deberías poder hacerte una idea más o menos clara sobre dónde está el error. Estará en la última línea que has añadido.
Si has copiado el código de un libro, comienza comparando detenidamente el original y su copia. Comprueba cada carácter, Recuerda que el libro puede contener errores, así que si algo parece un error de sintaxis, puede que lo sea.
He aquí una forma de evitar los errores de sintaxis más comunes:
Si nada de esto funciona, pasa a la siguiente sección.
Si el compilador informa de la existencia de un error y no consigues localizarlo, puede ser porque el compilador no está trabajando con el mismo código que tú. Comprueba tu entorno de desarrollo para asegurarte de que el programa que editas es el mismo que Python está intentando ejecutar. Si no estás seguro, intenta colocar un error de sintaxis obvio al comienzo del programa. Ahora ejecútalo (o impórtalo) de nuevo. Si el compilador no encuentra el nuevo error, entonces es que hay algún problema en la forma en la que está configurado el entorno.
Si esto sucede, una buena aproximación es comenzar de nuevo con un programa sencillo, del tipo «Hola Mundo», y asegurarte de puedes conseguir que se ejecute. Luego añade, gradualmente, las partes del programa nuevo al programa que funciona.
Una vez que la sintaxis de un programa es correcta, Python puede importarlo y -al menos- comenzar a ejecutarlo. ¿Qué puede fallar?
Este problema es común cuando el código se compone de funciones y clases, pero no llama a ninguna para comenzar la ejecución Esto puede ser intencionado, si el objetivo es importar el módulo como biblioteca de clases y funciones.
Si no, asegúrate de que estás llamando a una función para comenzar la ejecución, o ejecuta una desde la línea de comandos interactiva. Consulta también la sección «Flujo de la ejecución», más abajo.
Si un programa se para y parece que no hace nada, se dice que se ha «colgado». A menudo esto significa que está inmerso en un bucle infinito o en una recursión sin fin.
Ejecuta el programa. Si ves el primer mensaje, pero no el segundo, es que el programa ha entrado en un bucle infinito. Consulte la sección «Bucles infinitos» más abajo.
Aunque no obtengas este error, si sospechas que el problema podría estar en el método o la función recursivos, puedes usar las técnicas de la sección sobre recursión infinita.
Si crees haber identificado el problema en un bucle infinito concreto, añade una sentencia print al final del bucle para mostrar en pantalla los valores de las variables en la condición y el valor de esta.
Por ejemplo:
while
x > 0
and
y < 0 :
# hacer algo a x
# hacer algo a y
print
"x: ",
x
print
"y: ",
y
print
"condición: ",
(x > 0
and
y < 0)
Al ejecutar el programa, verás tres líneas con información por cada iteración del bucle. En la última, el valor de la condición debe ser false (falsa). Si el bucle se ejecuta sin fin, podrás ver los valores de x e y, y hacerte una idea de por qué no se actualizan correctamente.
Casi siempre, una recursión infinita dará lugar -tras un tiempo- al error «RuntimeError: Maximum recursion depth exceeded», indicando que se ha sobrepasado la profundidad máxima de recursión.
Si sospechas que algún método o función está provocando recursión infinita, comienza por comprobar que existe un caso terminal. En otras palabras, debe existir alguna condición que permita que la función o el método retornen sin provocar una llamada recursiva. Si no, debes replantear el algoritmo e identificar un caso terminal.
Si existe, pero el programa no parece alcanzarlo nunca, añade una sentencia print al comienzo de la función para mostrar en pantalla los parámetros. De esta forma, cuando ejecutes el programa verás unas cuantas líneas con información sobre los parámetros cada vez que se invoque al método o función. Así, si los parámetros no parecen tender hacia el caso terminal, podrás hacerte a la idea de por qué.
Si no estás seguro de cuál es el flujo de la ejecución en el programa, añade -al comienzo de cada función- una instrucción print que muestre un mensaje del tipo «entrada a la función nombre», donde nombre es el nombre de la función.
Así, al ejecutar el programa, se mostrará el orden en el que se llama a cada función.
Si algo falla en tiempo de ejecución, Python muestra un mensaje con el nombre de la excepción, la línea en la que ha ocurrido y un seguimiento.
El seguimiento identifica la función en ejecución, y luego la función que ha llamado a esta, y luego la función que ha llamado a aquella, y así sucesivamente. En otras palabras, traza el camino de las llamadas hasta llegar al punto actual. Además, incluye el número de línea en el que se produce cada una.
El primer paso es examinar el lugar del programa en el que se ha ocurrido el error, e intentar averiguar qué es lo que ha sucedido. He aquí los errores en tiempo de ejecución más comunes:
NameError
Error de nombre. Se está intentando usar una variable que no existe en el entorno activo. Recuerda que el ámbito de las variables es local. No puedes usarlas fuera de la función en la que han sido definidas.
TypeError
Error de tipo. Hay diferentes causas posibles:
KeyError
Error de clave. Se intenta acceder a un elemento de un diccionario usando una clave inexistente.
AttributeError
Error de atributo. Se intenta acceder a un atributo que no existe.
IndexError
Error de índice. El índice usado para acceder a una cadena, lista o tupla es mayor que su longitud menos uno. Añade una instrucción print inmediatamente antes del punto del error para mostrar el valor del índice y la longitud de la matriz. Comprueba que el índice es adecuado para el tamaño de la matriz.
Uno de los problemas de usar sentencias print en la depuración es que se puede acabar enterrado bajo tanto mensaje. Hay dos formas de proceder: simplificar los mensajes o simplificar el programa.
Para reducir los mensajes, puedes eliminar -o convertir en comentarios- las sentencias print prescindibles, o combinarlas entre sí o dar un formato a los mensajes que los haga más sencillos de entender.
Para simplificar el programa, puedes hacer varias cosas. Primero, intenta minimizar el problema con el que trata el programa. Por ejemplo, si sirve para ordenar una matriz, ordena una matriz pequeña. Si el programa recibe datos del usuario, proporciónale los datos más simples posibles para causar el problema.
Segundo, limpia el programa. Elimina el código inservible y reorganízalo para hacerlo lo más legible posible. Por ejemplo, si sospechas que el problema se produce en una parte profundamente anidada del programa, intenta rescribirlo usando una estructura más simple. Si crees que el error se encuentra en una función extensa, trata de dividirla en otras más pequeñas y pruébalas por separado.
Muy a menudo, este proceso ayuda a encontrar el error. Si un programa funciona en una situación determinada pero no en otra, esto puede indicar dónde está el problema.
De forma similar, rescribir una parte del código puede ayudar a encontrar errores soterrados. Si introduces un cambio que, en teoría, no debería afectar al funcionamiento del programa, pero lo hace, esto puede advertirte de la existencia de errores ocultos.
En cierto modo, este tipo de error es el más difícil de depurar, ya que ni el compilador ni el sistema proporcionan información sobre qué está fallando. Lo único cierto es que el programa no se está comportando como debería.
El primer paso es intentar encontrar una correspondencia entre el código del programa y el comportamiento que se observa. Necesitas formar una hipótesis acerca de qué es lo que el programa está haciendo. Uno de los inconvenientes que hacen esta tarea difícil es que los ordenadores funcionan muy rápido.
Muchas veces sería deseable que se pudiese ralentizar el programa hasta una velocidad humana, y con algunos depuradores es posible. Pero el tiempo que se emplea en intercalar algunas instrucciones print en el código es bastante menor que el que se tarda en configurar el depurador, añadir y eliminar puntos de interrupción y avanzar por el programa hasta el lugar en el que se produce el error.
Pregúntate lo siguiente:
Para programar necesitas un modelo mental de cómo funcionan los programas. Cuando un programa no se comporta como debería, es muy frecuente que esto se deba más al modelo mental que al programa en sí mismo.
La mejor manera de corregir tu modelo mental es dividir el programa en sus componentes -usualmente las funciones y los métodos- y comprobarlos por separado. Una vez que encuentres la discrepancia entre el modelo mental y la realidad, podrás resolver el problema.
Por supuesto, debes crear y comprobar los componentes a medida que desarrollas el programa. Si encuentras un problema, tan sólo debería haber una pequeña parte de código nuevo cuyo funcionamiento no ha sido comprobado.
Siempre y cuando sean legibles, no hay ningún problema por escribir expresiones largas, pero pueden ser difíciles de depurar. Una buena opción es dividir estas expresiones complejas en una serie de asignaciones temporales de variables.
Por ejemplo:
self.manos[i].agregarCarta (self.manos[self.buscarJugadorVecino(i)].tomarCarta())
Puede ser planteado así:
vecino
= self.buscarJugadorVecino (i)
cartaEscogida
= self.manos[vecino].tomarCarta()
self.manos[i].agregarCarta
(cartaEscogida)
La versión explícita es más sencilla de leer porque los nombres de variable añaden información adicional, y es más sencillo de depurar porque se puede determinar el tipo de las variables intermedias y mostrar sus valores.
Otro problema con las expresiones largas es que el orden en el que se evalúan puede diferir del esperado. Por ejemplo, para traducir a Python la expresión
|
x |
|
|
|
2 pi |
podrías escribir:
y = x / 2 * math.pi;
Esto no es correcto, ya que la multiplicación y la división tienen la misma prioridad en una expresión, y estas se evalúan de izquierda a derecha. Así, esta expresión es x pi / 2.
Una buena forma de depurar las expresiones es añadir paréntesis para explicitar el orden de evaluación:
y = x / (2 * math.pi);
Cuando no estés seguro del orden de evaluación, usa paréntesis. Esto no sólo conseguirá que el orden de evaluación sea el deseado, sino que además facilitará la lectura del programa a las personas que no conocen las reglas de precedencia.
Si tienes una instrucción return con una expresión compleja, no podrás imprimir el valor que devuelve antes de salir de la función o método. De nuevo, utiliza una variable temporal. Por ejemplo, en lugar de:
return self.manos[i].eliminarCoincidencias()
podrías escribir:
cuenta
= self.manos[i].eliminarCoincidencias()
return
cuenta
Así puedes mostrar el valor de cuenta antes de volver de la función o método.
Lo primero que debes hacer es alejarte del ordenador unos minutos. Los ordenadores emiten ondas que afectan al cerebro, causando:
Si sufres cualquiera de estos síntomas, levántate y da un paseo. Cuando estés tranquilo, piensa en el programa. ¿Qué está haciendo? ¿Cuáles son las posibles causas de este comportamiento? ¿Cuándo fue la última vez que funcionaba, y qué hiciste después?
A veces, encontrar un error no es más que cuestión de tiempo. A menudo, los errores se encuentran alejándose del ordenador y dejando la mente divagar. Algunos de los mejores lugares para encontrar errores son trenes, duchas y la cama, justo antes de dormir.
A veces ocurre. Hasta los mejores programadores se quedan atascados de vez en cuando. El trabajar mucho en un programa puede impedir encontrar sus errores. Cuatro ojos ven más que dos: busca ayuda.
Antes de involucrar a otra persona, asegúrate de que has agotado todas las técnicas descritas aquí. El programa debe ser tan simple como sea posible, y deberías haber encontrado el caso mínimo que provoca el error. Deberías tener instrucciones print en los lugares adecuados (y sus mensajes deberían ser comprensibles). Has de comprender el problema lo suficientemente bien como para describirlo de manera concisa.
Si alguien te va a ayudar, dale toda la información que necesita:
Cuando encuentres un error, piensa qué es lo que podrías haber hecho para encontrarlo más rápido. La próxima vez que veas algo parecido, serás capaz de encontrar el error rápidamente.
Recuerda: El objetivo no es sólo hacer que el programa funcione, sino aprender a hacerlo funcionar.
|
|
|
|
|
|
|
|