Herramientas Informaticas

Mes: agosto 2012 Página 21 de 22

20.6. Manejar errores

En todo momento hemos supuesto que las expresiones estaban bien formadas.

Por ejemplo, cuando alcanzamos el final de una subexpresion, suponemos que el carácter siguiente es un paréntesis cerrado. Si hay un error y el siguiente carácter es cualquier otra cosa, deber³amos ocuparnos de el.

   1: def obtieneNumero(listaToken):

   2:     if tomaToken(listaToken, '('):

   3:         x = obtieneSuma(listaToken)

   4:         if not tomaToken(listaToken, ')'):

   5:             raise 'ExpresionErronea', 'falta un par¶entesis'

   6:         return x

   7:     else:

   8:     # omitido el resto de la función

La sentencia raise crea una excepción; en este caso creamos un nuevo tipo de excepción, llamado ExpresionErronea. Si la función que llamo a obtieneNumero, o alguna de las otras funciones de la pila de llamadas, maneja la expresión, el programa podrá continuar. En caso contrario, Python imprimirá un mensaje de error y saldrá.

Como ejercicio, encuentre otros lugares de estas funciones donde
puedan ocurrir errores y añada las sentencias raise adecuadas.
Pruebe su código con expresiones formadas incorrectamente.

20.7. El árbol de animales

En esta sección desarrollaremos un pequeño programa que usa un árbol para representar una base de conocimientos.

El programa interactúa con el usuario para crear un árbol de preguntas y nombres de animales. Aquí tenemos un ejemplo de ejecución:

Estas pensando en un animal? s
Es un pájaro? n
Como se llama el animal? perro
Que pregunta distinguir³a a un perro de un pájaro? Puede volar
Si el animal fuera un perro, cual sería la respuesta? n
Estas pensando en un animal? s
Puede volar? n
Es un perro? n
Como se llama el animal? gato
Que pregunta distinguir³a a un gato de un perro? Ladra
Si el animal fuera un gato, cual ser³a la respuesta? n
Estas pensando en un animal? s
Puede volar? n
Ladra? s
Es un perro? s
Soy el mas grande!

Estas pensando en un animal? n

Este es el árbol que construye este dialogo:

Sin título

Al principio de cada ronda, el programa empieza en lo alto del árbol y hace la primera pregunta. Dependiendo de la respuesta, se mueve al hijo de la izquierda o de la derecha y sigue hasta que llega a un nodo hoja. En ese momento, intenta adivinar. Si falla, pide al usuario el nombre del nuevo animal y una pregunta que distinga al intento fallido del nuevo animal. Entonces a~nade un nodo al árbol con la nueva pregunta y el nuevo animal.

Este es el código:

   1: def animal():

   2: # empezar con un nodo suelto

   3: raiz = Arbol("pajaro")

   4: # bucle hasta que el usuario salga

   5: while 1:

   6: print

   7: if not si("Estas pensando en un animal? "): break

   8: # recorrer el arbol

   9: arbol = raiz

  10: while arbol.tomaIzquierda() != None:

  11: indicador = arbol.tomaCarga() + "? "

  12: if si(indicador):

  13: arbol = arbol.tomaDerecha()

  14: else:

  15: arbol = arbol.tomaIzquierda()

  16: # intentar adivinar

  17: adivina = arbol.tomaCarga()

  18: indicador = "Es un " + adivina + "? "

  19: if si(indicador):

  20: print "Soy el mas grande!"

  21: continue

  22: # obtener informacion nueva

  23: indicador = "Como se llama el animal? "

  24: animal = raw_input(indicador)

  25: indicador = "Que pregunta distinguir³a a un %s de un %s? "

  26: pregunta = raw_input(indicador % (animal,adivina))

  27: # añadir informacion nueva al arbol

  28: arbol.ponCarga(pregunta)

  29: indicador = "Si el animal fuera un %s, cual ser³a la

  30: respuesta? "

  31: if si(indicador % animal):

  32: arbol.ponIzquierda(Arbol(adivina))

  33: arbol.ponDerecha(Arbol(animal))

  34: else:

  35: arbol.ponIzquierda(Arbol(animal))

  36: arbol.ponDerecha(Arbol(adivina))

 

La función si es un auxiliar; imprime un indicador y acepta una entrada del usuario. Si la respuesta comienza con s o S, la función devuelve verdadero:

   1: def si(preg):

   2: from string import lower

   3: resp = lower(raw_input(preg))

   4: return (resp[0] == 's')

La condición del bucle externo es 1, lo que significa que seguirá hasta que se ejecute la sentencia break cuando el usuario ya no piense en ningún animal.

El bucle while interno recorre el árbol de arriba a abajo, guiado por las respuestas del usuario.

Cuando se añade un nuevo nodo al árbol, la pregunta sustituye a la carga y los dos hijos son el animal nuevo y la carga original.

Una carencia del programa es que, al salir, <olvida todo lo que usted le había enseñado con tanto cuidado!

Como ejercicio, piense en varias formas en las que podría guardar el árbol de conocimiento en un archivo. Implemente la que piense que es mas fácil.

20.8. Glosario

árbol binario: Un árbol en el que cada nodo apunta a cero, uno, o dos nodos dependientes.

raíz: El nodo superior de un árbol, sin padre.

hoja: Un nodo del extremo inferior de un árbol, sin hijos.

padre: El nodo que apunta a un nodo dado.

hijo: Uno de los nodos a los que apunta un nodo.

hermanos: Nodos que tienen un padre común.

nivel: El conjunto de nodos equidistante de la raíz.

operador binario: Un operador que toma dos operandos.

subexpresión: Una expresión entre paréntesis que actúa como un operando simple dentro de otra expresión mayor.orden prefijo: Una forma de recorrer un árbol, visitando cada nodo antes que a sus hijos.

notación prefija: Una forma de escribir una expresión matemática en la que los operadores aparecen antes que sus operandos.

orden postfijo: Una forma de recorrer un árbol, visitando los hijos de cada nodo antes del propio nodo.

orden infijo: Una forma de recorrer un árbol, visitando el subárbol izquierdo, luego la raíz, y luego el subárbol derecho.

Apéndice A

Depuración

En un programa pueden suceder varios tipos de error, y resulta útil distinguirlos para localizarlos rápidamente:

  • Python presenta errores de sintaxis mientras traduce el código fuente en código binario. Normalmente indican que hay algo erróneo en la sintaxis del programa. Ejemplo: omitir los dos puntos al final de una sentencia def nos da el mensaje SyntaxError: invalid syntax, algo redundante.
  • El sistema de tiempo de ejecución presenta los errores en tiempo de ejecución si algo va mal mientras se ejecuta el programa. La mayoría de los mensajes de error en tiempo de ejecución incluyen información acerca de donde sucedió el error y que funciones se estaban ejecutando. Ejemplo: una recursión infinita termina por provocar un error en tiempo de ejecución del máximum recursión depth exceeded” (superada la profundidad máxima de recursión).
  • Los errores semánticos son problemas con un programa que compila y se ejecuta pero no hace lo que se espera de el. Ejemplo: una expresión puede no evaluarse en el orden esperado, dando un resultado inesperado.

El primer paso de la depuración es averiguar con que tipo de error se enfrenta.

Aunque las secciones que siguen están organizadas por tipos de error, algunas tecnicas son aplicables en mas de una situación.

A.1. Errores de sintaxis

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 mas comunes son SyntaxError: invalid syntax y SyntaxError: invalid token, ninguno de los cuales es muy informativo.Por otra parte, el mensaje le dice en que lugar del programa sucedió el error.

En realidad, le dice donde noto el problema Python, que no es necesariamente donde esta el error. A veces el error esta antes de la localización del mensaje de error, muchas veces en la línea anterior.

Si esta haciendo el programa incrementalmente, deber³a tener casi localizado el error. Estará en la ultima línea que añadió.

Si esta 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 mas habituales:

  1. Asegúrese de que no utiliza una palabra clave de Python como nombre de variable.
  2. Compruebe que tiene los dos puntos al final de la cabecera de todas las sentencias compuestas, las for, while, if, y def.
  3. Compruebe que el sangrado es consistente. Puede usted sangrar tanto con espacios como con tabuladores, pero es mejor no mezclarlos. Todos los niveles deberían estar anidados por la misma cantidad.
  4. Asegúrese de que todas las cadenas del código tienen su par de comillas de apertura y cierre.
  5. Si tiene cadenas que ocupan varias l³neas con triples comillas (o triples apóstrofos), asegúrese de que ha terminado la cadena correctamente. Una cadena sin terminar puede provocar un error invalid token al final de su programa, o puede tratar la siguiente parte del programa como una cadena hasta que llegue a la siguiente cadena. <En el segundo caso, podría no presentar ningún mensaje de error!
  6. Un paréntesis sin cerrar|(, { o [|hace que Python continue con la línea siguiente como parte de la sentencia actual. Generalmente aparecerá un error casi inmediatamente en la l³nea siguiente.
  7. Compruebe el clásico = donde debería haber un == en los condicionales.

Si nada funciona, siga con la sección que sigue…

A.1.1. No consigo ejecutar mi programa, no importa lo que haga

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 esta editando es el que esta intentando ejecutar Python. Si no esta 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 probablemente hay algo equivocado en el modo en que esta 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~nada gradualmente los trozos del programa nuevo al que funciona.

A.2. Errores en tiempo de ejecución

Una vez que su programa es sintácticamente correcto, Python pude importarlo
y al menos comenzar a ejecutarlo.

Que podría ir mal?

A.2.1. Mi programa no hace nada de nada.

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 solo planea importar el modulo para suministrar clases y
funciones.

Sin no es intencionado, asegúrese de que esta 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” mas adelante.

A.2.2. Mi programa se cuelga.

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 hay un bucle en particular que le resulta sospechoso de provocar el problema, añada una sentencia print justo antes del bucle que diga entrando al bucle” y otra inmediatamente después que diga saliendo del bucle”.
  • Ejecute el programa. Si obtiene el primer mensaje pero el segundo no, tiene usted un bucle infinito. Vaya a la sección Bucle Infinito” mas adelante.
  • Una recursión infinita casi siempre hará que el programa corra un rato y luego presente un error de RuntimeError: Máximum recursión depth exceeded”. Si ocurre eso, vaya a la sección Recursión Infinita” mas adelante.
  • Si no ve este error pero sospecha que hay un problema con un método o función recursivos también puede utilizar las tecnicas de la sección Recursión Infinita”.
  • Si no funciona ninguno de estos pasos, comience a probar otros bucles y otros metodos y funciones recursivos.
  • Si eso no funciona, es posible que no comprenda el flujo de ejecución de su programa. Vaya a la sección Flujo de Ejecución” mas adelante.

Página 21 de 22

Creado con WordPress & Tema de Anders Norén