![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
En un programa pueden suceder varios tipos de error, y resulta útil distinguirlos para localizarlos rápidamente:
El primer paso de la depuración es averiguar con qué tipo de error se enfrenta. Aunque las secciones que siguen están organizadas por tipos de error, algunas técnicas son aplicables en más de una situación.
Los errores de sintaxis suelen ser fáciles de arreglar una vez que averigua lo que son. Desgraciadamente, muchas veces los mensajes de error no son muy útiles. Los mensajes más comunes son SyntaxError: invalid syntax y SyntaxError: invalid token, ninguno de los cuales es muy informativo.
Por otra parte, el mensaje le dice en qué lugar del programa sucedió el error. En realidad, le dice dónde notó el problema Python, que no es necesariamente donde está el error. A veces el error está antes de la localización del mensaje de error, muchas veces en la línea anterior.
Si está haciendo el programa incrementalmente, debería tener casi localizado el error. Estará en la última línea que añadió.
Si está usted copiando código de un libro, comience comparando con atención su código con el del libro. Compruebe cada carácter. Al mismo tiempo, recuerde que el libro podría estar equivocado, así que si ve algo que parezca un error de sintaxis, podría serlo.
He aquí algunas formas de evitar los errores de sintaxis más habituales:
Si nada funciona, siga con la sección que sigue...
Si el compilador dice que hay un error pero usted no lo ve, podría ser porque usted y el compilador no miran el mismo código. Compruebe su entorno de programación para asegurarse de que el programa que está editando es el que está intentando ejecutar Python. Si no está seguro, pruebe a poner un error de sintaxis obvio y deliberado al principio del programa. Ahora ejecute (o importe) de nuevo. Si el compilador no encuentra el nuevo error probalemente hay algo equivocado en el modo en que está configurado su entorno.
Si esto ocurre, puede enfrentarse a ello empezando de nuevo con un programa nuevo como "Hola, mundo", y asegurarse de que puede hacer que funcione un programa conocido. Luego añada gradualmente los trozos del programa nuevo al que funciona.
Una vez que su programa es sintácticamente correcto, Python pude importarlo y al menos comenzar a ejecutarlo. ¿Qué podría ir mal?
Este problema es muy común cuando su archivo consta de funciones y clases pero en realidad no invoca nada para que empiece la ejecución. Esto puede ser intencionado cuando sólo planea importar el módulo para suministrar clases y funciones.
Sin no es intencionado, asegúrese de que está llamando a una función que inicie la ejecución, o ejecute una desde el indicador interactivo. Vea también la sección "Flujo de Ejecución" más adelante.
Si un programa se para y parece no hacer nada, decimos que "se ha colgado". A menudo significa que se ha quedado atrapado en un bucle infinito o en una recursión infinita.
Si cree que tiene un bucle infinito y piensa que sabe qué bucle provoca el problema, añada una sentencia print que imprima los valores de las variables de la condición al final del bucle junto con el valor de la condición.
Por ejamplo:
while x > 0 and y < 0 :
# hacer algo con x
# hacer algo con y
print "x: ", x
print "y: ", y
print "condición: ", (x > 0 and y < 0)
Ahora, cuando ejecute el programa, verá tres líneas de salida en cada vuelta del bucle. En la última vuelta el valor de la condición debería ser false. Si el bucle sigue ejecutándose, podrá ver los valores de x e y, y podrá averiguar por qué no se actualizan correctamente.
Una recursión infinita casi siempre hará que el programa se ejecute
un rato y luego provoque un error de Maximum recursion depth
exceeded.
Si sospecha que una función o un método está causando una recursión infinita, comience por asegurarse de que hay un caso básico. En otras palabras, debería haber una condición que haga que la función devuelva un valor sin hacer otra llamada recursiva. Si no, necesita revisar el algoritmo y encontrar ese caso básico.
Si hay un caso básico pero el programa no parece llegar hasta él, añada una sentencia print que imprima los parámetros al principio de la función o método. Cuando ahora ejecute el programa, verá unas pocas líneas cada vez que se invoque la función o método y allí verá los parámetros. Si los parámetros no se acercan al caso básico, eso le dará alguna idea de por qué no lo hace.
Si no está seguro de qué curso sigue el flujo de ejecución en su programa, añada sentencias print al principio de cada función con un mensaje como "entrando en la función tururú", donde tururú es el nombre de la función.
Cuando ahora ejecute el programa, imprimirá una traza de cada función a medida que las vaya invocando.
Si algo va mal durante la ejecución, Python imprime un mensaje que incluye el nombre de la excepción, la línea del programa donde sucedió el problema y una traza inversa.
La traza inversa identifica la función que se está ejecutando ahora y la función que invocó a ésta, y luego la función que invocó a ésa, y así sucesivamente. En otras palabras, traza la ruta de las llamadas a las funciones que le llevaron a donde se encuentra. También incluye los números de las líneas de sus archivos donde suceden todas esas llamadas.
El primer paso es examinar el lugar del programa donde sucede el error y ver si puede adivinar lo que sucedió. Estos son algunos de los errores en tiempo de ejecución más comunes:
Uno de los problemas de usar sentencias print para la depuración es que puede terminar enterrado en información. Hay dos formas de atajar el problema: simplificar la salida o simplificar el programa.
Para simplificar la salida, puede elimiar o comentar (convertir en comentarios) las sentencias print que no sean de ayuda, o combinarlas, o dar a la salida un formato que la haga más comprensible.
Para simplificar el programa puede hacer varias cosas. Primero, reducir la escala del problema en el que está trabajando el programa. Por ejemplo, si está ordenando un vector, ordene un vector pequeño. Si el programa acepta entradas del usuario, dele la entrada más simple que provoque el problema.
Segundo, limpie el programa. Elimine el código muerto y reorganice el programa para hacerlo tan legible como sea posible. Por ejemplo, si sospecha que el problema está en una parte del programa con un anidamiento muy profundo, pruebe a reescribir esa parte con una estructura más simple. Si sospecha de una función grande, trate de trocearla en funciones menores y pruébelas separadamente.
El proceso de encontrar el caso mínimo de prueba le llevará a menudo al error. Si se encuentra con que un programa funciona en una situación pero no en otra, eso le dará una pista sobre lo que ocurre.
De forma parecida, la reescritura de una porción de código puede ayudarle a encontrar errores sutiles. Si hace un cambio que a usted le parece que no afecta al programa, pero sí lo hace, le dará una pista.
En cierto modo, los errores semánticos son los más difíciles de corregir, porque el compilador y el sistema de ejecución no proporcionan información sobre lo que va mal. Sólo usted sabe lo que se supone que debe hacer el programa, y sólo usted sabe que no lo está haciendo.
El primer paso es hacer una concexión entre el texto del programa y el comportamiento que está usted viendo. Necesita una hipótesis sobre lo que realmente está haciendo el programa. Una de las dificultades que nos encontramos para ello es la alta velocidad de los computadores.
A menudo desearía ralentizar el progrma a una velocidad humana, y con algunos programas depuradores podrá hacerlo. Pero el tiempo que lleva colocar unas sentencias print en los lugares adecuadoes suele ser menor que el que lleva configurar el depurador, poner y quitar puntos de interrupción y "hacer caminar" el programa hasta donde se produce el error.
Debería hacerse estas preguntas:
Para programar necesitará tener un modelo mental de cómo funcionan los programas. Si escribe un programa que no hace lo que espera de él, muchas veces el problema no estará en el programa, sino en su modelo mental.
La mejor manera de corregir su modelo mental es dividiendo el programa en sus componentes (normalmente las funciones y métodos) y probando cada componente de forma independiente. Una vez que encuentre la discrepancia entre su modelo y la realidad, podrá solucionar el problema.
Por supuesto, debería ir haciendo y probando componentes tal como desarrolla el programa. Si encuentra un problema, sólo habrá una pequeña cantidad de código nuevo del que no sabe si está correcto.
Está bien escribir expresión complejas mientras sean legibles, pero pueden ser difíciles de depurar. Suele ser una buena idea dividir una expesión compleja en una serie de asignaciones de variables temporales.
Por ejamplo:
self.manos[i].agregaCarta (self.manos[\
self.encuentraVecino(i)].darCarta())
Puede reescribirse como:
vecino = self.encuentraVecino (i)
cartaElegida = self.manos[vecino].darCarta()
self.manos[i].agregaCarta (cartaElegida)
La versión explícita es más fácil de leer porque los nombres de variable nos facilitan documentación adicional, y es más fácil de depurar porque puede comprobar los tipos de las variables intermedias y mostrar sus valores.
Otro problema que puede suceder con las expresiones grandes es que el orden
de evaluación puede no ser el que usted esperaba. Por ejemplo, si está
traduciendo la expresión
a Python, podría escribir:
x 2 pi
y = x / 2 * math.pi;
Eso no es correcto, porque la multiplicación y la división tienen la misma precedencia y se evalúan de izquierd a derecha. Así que esa expresión calcula x pi / 2.
Una buena forma de depurar expresiones es añadir paréntesis para hacer explícito el orden de evaluación:
y = x / (2 * math.pi);
Siempre que no esté seguro del orden de evaluación, utilice paréntesis. El programa no sólo será correcto (en el sentido de hacer lo que usted prentendía), sino que además será más legible para otras personas que no hayan memorizado las reglas de precedencia.
Si tiene una sentencia return con una expresión compleja no tendrá la oportunidad de imprimir el valor de retorno antes de volver. De nuevo, puede usar una variable temporal. Por ejemplo, en lugar de:
return self.manos[i].eliminaCoincidencias()
podría excribir:
cant = self.manos[i].eliminaCoincidencias()
return cant
Ahora ya tiene la oportunidad de mostrar el valor de cant antes de regresar.
Primero, intente alejarse del computador durante unos minutos. Los computadores emiten unas ondas que afectan al cerebro provocando estos efectos:
Si se encuentra afectado por alguno de estos síntomas, levántese y dé un paseo. Cuando esté calmado, piense en el programa. ¿Qué es lo que hace? ¿Cuáles pueden ser las causas de tal comportamiento? ¿Cuándo fue la última vez que tenía un programa que funcinaba y qué fue lo siguiente que hizo?
A veces lleva tiempo encontrar un error. Muchas veces encontramos errores cuando estamos lejos del computador y divagamos. Algunos de los mejores lugares para encontrar errores son los trenes, las duchas y la cma, justo antes de quedarse dormido.
Sucede. Incluso los mejores programadores se atascan de vez en cuando. A veces trabaja durante tanto tiempo en un programa que no puede ver el error. Lo que necesita es un par de ojos nuevos.
Antes de llamar a andie, asegúrese de que ha agotado las técnicas explicadas aquí. Su programa debería ser tan simple como sea posible, y usted debería estar trabajando con la entrada mínima que provoca el error. Debería tener sentencias print en los lugares adecuados (y lo que dicen debería ser comprensible). Debería entender el problema lo bastante bien como para describirlo sucintamente.
Cuando llame a alguien para que le ayude, asegúrese de darles la información que necesitan:
Cuando encuentre el error, tómese un momento para pensar acerca de lo que podría haber hecho para encontrarlo más rápido. La siguiente vez que vea algo parecido, será capaz de encontrar el error antes.
Recuerde, el objetivo no es sólo hacer que el programa funciones. El objetivo es aprender cómo hacer funcionar al programa.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |