Manejo de errores y excepciones

Anuncio
Universidad de Costa Rica | Escuela de Ingeniería Eléctrica
IE-0117 Programación Bajo Plataformas Abiertas
Manejo de errores y excepciones
En un programa de cómputo es necesario manejar de forma adecuada los posibles errores que puedan surgir, con el
fin de que el usuario experimente la menor cantidad posible de problemas. El programador debe ser capaz de reconocer
los posibles problemas que puedan presentarse durante la ejecución del programa y tomar las acciones necesarias para
que el error no produzca resultados incorrectos o provoque que la aplicación se cierre de manera abrupta.
Además, el programador debe asegurarse de que el programa notifique al usuario, a través de mensajes de error, los
problemas que se presenten. De esta manera, el usuario puede tomar las acciones necesarias para corregir la situación y
utilizar el programa de forma exitosa. Los mensajes de error deben ser claros y descriptivos, para facilitar su comprensión
por parte de usuarios sin experiencia.
1.
Prácticas recomendadas para el manejo de errores
1.1. Verificación de la cantidad de argumentos de entrada
Si el usuario no proporciona la cantidad correcta de argumentos en la línea de comandos, el programa no funcionará
adecuadamente. Puede verificarse la cantidad de argumentos con una prueba simple al inicio de programa:
import sys
if len(sys.argv) != NUM_ARGS:
# Imprime mensajes de error
print >> sys.stderr, "Número de argumentos incorrecto"
print >> sys.stderr, "Uso: %s a b c" % sys.argv[0]
# Termina regresando un "1" al shell para indicar error
sys.exit(1)
...
1.2. Pruebas sobre los argumentos
Si se trata de convertir una cadena a otro tipo de datos y el contenido de la cadena no es el adecuado se producirá
un error. Es posible usar funciones como isdigit() antes de la conversión para verificar que la cadena sea convertible.
Pueden hacerse verificaciones avanzadas usando otras herramientas como las expresiones regulares1 . Las expresiones
regulares permiten definir patrones abstractos (por ejemplo direcciones de correo o números de teléfono) que se buscarán
dentro de una cadena.
1.3. Verificación de existencia de directorios y arivos
Es conveniente verificar la existencia de rutas de archivos y directorios proporcionadas por el usuario antes de intentar
accederlas. Para esto pueden usarse algunas funciones del módulo os.path:
exists():
isdir():
isfile():
retorna True si la ruta existe, sea un archivo o directorio.
retorna True si la ruta corresponde a un directorio que existe en el sistema.
retorna True si la ruta corresponde a un archivo convencional en el sistema.
1 http://docs.python.org/library/re.html
1
IE-0117 Programación Bajo Plataformas Abiertas
Manejo de errores y excepciones
1.4. Valores de retorno adecuados en las funciones
En caso de que se de un error en una función, esta debe retornar un valor adecuado que pueda ser detectado por el
programador que usa la función. Una buena práctica es retornar explícitamente None cuando se produce un error:
def test_float(num):
cont_puntos = 0
for char in num:
if char == '.':
cont_puntos += 1
elif not char.isdigit():
# Hay caracteres no numéricos
return None
if cont_puntos > 1:
# Hay más de un punto
return None
else:
# Si todo salió bien retorna número convertido
return float(num)
En este caso, la función test_float() retorna None si la cadena que se trata de convertir a float contiene caracteres
no numéricos o más de un carácter punto. De esta forma es posible capturar el posible error al llamar a la función:
a = raw_input("Ingrese un número: ")
na = test_float(a)
if not na:
# test_float(a) retornó None, 'a' no era un número de punto flotante
...
else:
# Todo bien, puede continuar el programa
...
2.
Excepciones
Python, al igual que la mayoría de los lenguajes de programación orientados a objetos, provee un mecanismo para
el manejo de errores muy eficiente: las excepciones. Una excepción es una condición que se dispara automáticamente
cuando se produce un error. Si la excepción no se captura, el intérprete imprimirá un mensaje de error y cerrará el
programa. Sin embargo, es posible capturar la excepción y mover el flujo del programa a una rutina especial para
manejo de errores que se ejecutará sólo cuando se de el error.
2.1. Captura de excepciones
Suponga que se solicita al usuario un valor, el cual será convertido a un número de punto flotante:
a = raw_input("Ingrese un número: ")
na = float(a)
Si el usuario introduce un valor erróneo se producirá entonces una excepción que, si no es capturada, imprimirá el
siguiente mensaje y cerrará el programa:
Traceback (most recent call last):
...
ValueError: invalid literal for float(): 12.4asb
2
IE-0117 Programación Bajo Plataformas Abiertas
Manejo de errores y excepciones
Es posible capturar la excepción usando la palabra clave except para manejar el error adecuadamente:
try:
a = raw_input("Ingrese un número: ")
na = float(a)
except ValueError:
print >>sys.stderr, "El valor introducido no es un número"
...
Cada vez que se produce una excepción se genera un objeto con un tipo determinado. El tipo de este objeto es el que
indica la clase de excepción que se produce. En el ejemplo anterior, la excepción que se produce es del tipo ValueError,
que se da cuando el valor que se pasa a una función u operador no es el correcto. El enunciado except indica que se
capturará específicamente este tipo de excepción. Si se produjera una excepción de otro tipo, esta no sería manejada.
Es posible capturar varios tipos de excepciones en un mismo enunciado except, usando una tupla:
try:
a = raw_input("Ingrese un número: ")
na = float(a)
except (ValueError, NameError, IOError):
print >>sys.stderr, "Se produjo un error"
...
También es posible usar varios bloques except, para procesar distintas excepciones por separado:
try:
a = raw_input("Ingrese un número: ")
na = float(a)
except ValueError:
print >>sys.stderr, "El valor introducido no es un número"
except IOError:
print >>sys.stderr, "Se produjo un error de Entrada/Salida"
...
Todos los tipos de datos de excepción tienen una clase base llamada Exception. Esto permite crear un bloque except
que captura una excepción genérica:
try:
a = raw_input("Ingrese un número: ")
na = float(a)
except ValueError:
print >>sys.stderr, "El valor introducido no es un número"
except Exception:
# Captura una excepción genérica
print >>sys.stderr, "Se produjo un error"
...
3
IE-0117 Programación Bajo Plataformas Abiertas
Manejo de errores y excepciones
Además del bloque try... except, puede agregarse un bloque else, que define un bloque de código que se ejecutará
si la excepción no se produce:
try:
a = raw_input("Ingrese un número: ")
na = float(a)
except ValueError:
print >>sys.stderr, "El valor introducido no es un número"
else:
# No se produjo la excepción, puede usarse la variable na
...
También existe el bloque finally, que permite definir código que será ejecutado siempre, sin importar si se produce
o no la excepción. Este bloque es útil para realizar tareas de limpieza y liberación de recursos:
try:
datos = f.readlines()
except IOError:
print >> sys.stderr, "Error leyendo datos desde el archivo"
finally:
# Cierra el archivo, haya o no haya excepción
f.close()
2.2. Excepciones comunes
Algunos tipos de datos de excepción comunes son:
ValueError:
IOError:
Se produce cuando se pasa un valor incorrecto a una función u operador.
Error de entrada/salida (por ejemplo al leer datos de un archivo).
KeyboardInterrupt:
IndexError:
KeyError:
Ocurre cuando el usuario oprime las teclas Ctrl-c.
Se produce cuando se trata de acceder a un elemento de una lista que no existe.
Se da cuando se trata de acceder a un elemento de un diccionario con una llave que no existe.
ZeroDivisionError:
Se produce cuando se trata de dividir entre cero.
TypeError:
Error de tipo. Se produce cuando un operador o función recibe un dato con un tipo distinto al esperado.
NameError:
Ocurre cuando se trata de utilizar una variable, clase o función que no se ha definido.
ImportError:
Se da cuando se trata de importar un módulo que no existe.
Los módulos, tanto los que forman parte de la biblioteca estándar como los provistos por terceras partes, pueden
definir nuevas excepciones, que se adapten a las necesidades específicas de cada caso.
4
IE-0117 Programación Bajo Plataformas Abiertas
Manejo de errores y excepciones
2.3. Acceso al objeto excepción
Es posible tener acceso al objeto excepción durante la captura, usando un argumento extra en el enunciado except:
try:
a = raw_input("Ingrese un número: ")
na = float(a)
except ValueError, error:
print >>sys.stderr, "El valor introducido no es un número"
print >>sys.stderr, "Información adicional:", error
...
Si se produce el error se imprimiría:
El valor introducido no es un número
Información adicional: invalid literal for float(): 12.4asb
Algunas excepciones proporcionan información adicional a través de métodos o propiedades, que puede ser de valor
en algunos casos.
2.4. Disparo de excepciones
Es posible generar exepciones en un punto arbitrario de un programa. Esto es particularmente útil cuando se están
creando funciones o módulos que se utilizarán luego en otras partes del programa.
Por ejemplo, podría escribirse una función que utilice excepciones para asegurar que el número que recibe como
argumento sea positivo
def mi_funcion(a):
import math
if a < 0:
raise ValueError("El número debe ser positivo")
else:
return math.sqrt(a) + 9.80
Al llamar a la función puede usarse entonces un bloque try... except:
try:
print mi_funcion(x)
except ValueError, e:
print >>sys.stderr, "Error:", e
2.5. Creación de excepciones personalizadas
Es posible crear excepciones personalizadas utilizando nuevas clases, basadas en Exception:
class MiExcepcion(Exception):
def __init__(self, desc):
self.desc = desc
def __str__(self):
return self.desc
Una vez definida, la excepción podría dispararse como cualquier otra:
5
IE-0117 Programación Bajo Plataformas Abiertas
Manejo de errores y excepciones
raise MiExcepcion("Error, Error!")
y luego podría ser capturada:
try:
# Código que podría provocar errores
...
except MiExcepcion, e:
# Código para manejar el error
...
6
Descargar