Subsecciones


8. Errores y excepciones

Hasta ahora no habíamos más que mencionado los mensajes de error, pero si has probado los ejemplos puede que hayas visto algunos. Hay (al menos) dos tipos de errores diferenciables: los errores de sintaxis y las excepciones.


8.1 Errores de sintaxis

Los errores de sintaxis son la clase de queja más común del intérprete cuando todavía estás aprendiendo Python:

>>> while 1 print 'Hola mundo'
  File "<stdin>", line 1
    while 1 print 'Hola mundo'
                ^
SyntaxError: invalid syntax

El intérprete sintáctico repite la línea ofensiva y presenta una `flechita' que apunta al primer punto en que se ha detectado el error. La causa del error está (o al menos se ha detectado) en el símbolo anterior a la flecha: En este ejemplo, el error se detecta en la palabra clave print, porque faltan los dos puntos (":") antes de ésta. Se muestran el nombre del fichero y el número de línea para que sepas dónde buscar, si la entrada venía de un fichero.


8.2 Excepciones

Aun cuando una sentencia o expresión sea sintácticamente correcta, puede causar un error al intentar ejecutarla. Los errores que se detectan en la ejecución se llaman excepciones y no son mortales de necesidad, pronto va a aprender a gestionarlos desde programas en Python. Las excepciones no capturadas causan mensajes de error como el siguiente:

>>> 10 * (1/0)
Traceback (innermost last):
  File "<stdin>", line 1
ZeroDivisionError: integer division or modulo
>>> 4 + fiambre*3
Traceback (innermost last):
  File "<stdin>", line 1
NameError: fiambre
>>> '2' + 2
Traceback (innermost last):
  File "<stdin>", line 1
TypeError: illegal argument type for built-in operation

La última línea del mensaje de error indica qué ha pasado. Las excepciones pueden ser de diversos tipos, que se presentan como parte del mensaje: los tipos del ejemplo son ZeroDivisionError, NameError y TypeError. La cadena presentada como tipo de excepción es el nombre interno de la excepción que ha ocurrido. Esto es aplicable a todas las excepciones internas, pero no es necesariamente cierto para las excepciones definidas por el usuario (sin embargo, es una útil convención). Los nombres de excepciones estándar son identificadores internos (no palabras reservadas).

El resto de la línea contiene detalles cuya interpretación depende del tipo de excepción.

La parte anterior al mensaje de error muestra el contexto donde ocurrió la excepción, en forma de trazado de la pila. En general, contiene un trazado que muestra las líneas de código fuente, aunque no mostrará las líneas leídas de la entrada estándar.

La Referencia de las bibliotecas enumera las excepciones internas y sus respectivos significados.


8.3 Gestión de excepciones

Es posible escribir programas que gestionen ciertas excepciones. Mira el siguiente ejemplo, que pide datos al usuario hasta que se introduce un entero válido, pero permite al usuario interrumpir la ejecución del programa (con Control-C u otra adecuada para el sistema operativo en cuestion); Observa que una interrupción generada por el usuario se señaliza haciendo saltar la excepcion KeyboardInterrupt.

>>> while 1:
...     try:
...         x = int(raw_input("Introduce un número: "))
...         break
...     except ValueError:
...         print "¡Huy! No es un número. Prueba de nuevo..."
...

La sentencia try funciona de la siguiente manera:

Una sentencia try puede contener más de una cláusula except, para capturar diferentes excepciones. Nunca se ejecuta más de un gestor para una sola excepción. Los gestores sólo capturan excepciones que saltan en la cláusula try correspondiente, no en otros gestores de la misma sentencia try. Una cláusula try puede capturar más de una excepción, nombrándolas dentro de una lista:

... except (RuntimeError, TypeError, NameError):
...     pass

La última cláusula except puede no nombrar ninguna excepción, en cuyo caso hace de comodín y captura cualquier excepción. Se debe utilizar esto con mucha precaución, pues es muy fácil enmascarar un error de programación real de este modo. También se puede utilizar para mostrar un mensaje de error y relanzar la excepción (permitiendo de este modo que uno de los llamantes gestione la excepción a su vez):

import string, sys

try:
    f = open('mifichero.txt')
    s = f.readline()
    i = int(string.strip(s))
except IOError, (errno, strerror):
    print "Error de E/S(%s): %s" % (errno, strerror)
except ValueError:
    print "No ha sido posible covertir los datos a entero."
except:
    print "Error no contemplado:", sys.exc_info()[0]
    raise

La sentencia try ... except tiene una cláusula else opcional, que aparece tras las cláusulas except. Se utiliza para colocar código que se ejecuta si la cláusula try no hace saltar ninguna excepción. Por ejemplo:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'no se puede abrir', arg
    else:
        print arg, 'contiene', len(f.readlines()), 'líneas'
        f.close()

El uso de la cláusula else es mejor que añadir código adicional a la cláusula try porque evita que se capture accidentalemente una excepción que no fue lanzada por el código protegido por la sentencia try ... except.

Cuando salta una excepción, puede tener un valor asociado, también conocido como el/los argumento/s de la excepción. Que el argumento aparezca o no y su tipo dependen del tipo de excepción. En los tipos de excepción que tienen argumento, la cláusula except puede especificar una variable tras el nombre de la excepción (o tras la lista) que recibirá el valor del argumento, del siguiente modo:

>>> try:
...     fiambre()
... except NameError, x:
...     print 'nombre', x, 'sin definir'
... 
nombre fiambre sin definir

Si una excepción no capturada tiene argumento, se muestra como última parte (detalle) del mensaje de error.

Los gestores de excepciones no las gestionan sólo si saltan inmediatamente en la cláusula try, también si saltan en funciones llamadas (directa o indirectamente) dentro de la cláusula try. Por ejemplo:

>>> def esto_casca():
...     x = 1/0
... 
>>> try:
...     esto_casca()
... except ZeroDivisionError, detalle:
...     print 'Gestión de errores:', detalle
... 
Gestión de errores: integer division or modulo


8.4 Hacer saltar excepciones

La sentencia raise (hacer saltar) permite que el programador fuerce la aparición de una excepción. Por ejemplo:

>>> raise NameError, 'MuyBuenas'
Traceback (innermost last):
  File "<stdin>", line 1
NameError: MuyBuenas

El primer argumento para raise indica la excepción que debe saltar. El segundo argumento, opcional, especifica el argumento de la excepción.


8.5 Excepciones definidas por el usuario

Los programas pueden nombrar sus propias excepciones asignando una cadena a una variable o creando una nueva clase de excepción. Por ejemplo:

>>> class MiError:
...     def __init__(self, valor):
...         self.valor = valor
...     def __str__(self):
...         return `self.valor`
... 

>>> try:
...     raise raise MiError(2*2)
... except MiError, e:
...     print 'Ha saltado mi excepción, valor:', e.valor
... 
Ha saltado mi excepción, valor: 4
>>> raise mi_exc, 1
Traceback (innermost last):
  File "<stdin>", line 1
mi_exc: 1

Muchos módulos estándar utilizan esto para informar de errores que pueden ocurrir dentro de las funciones que definen.

Hay más información sobre las clases en el capítulo , ``Clases''.


8.6 Definir acciones de limpieza

La sentencia try tiene otra cláusula opcional cuya intención es definir acciones de limpieza que se han de ejecutar en cualquier circunstancia. Por ejemplo:

>>> try:
...     raise KeyboardInterrupt
... finally:
...     print '¡Adiós, mundo cruel!'
... 
¡Adiós, mundo cruel!
Traceback (innermost last):
  File "<stdin>", line 2
KeyboardInterrupt

La cláusula finally (finalmente) se ejecuta tanto si ha saltado una excepción dentro de la cláusula try como si no. Si ocurre una excepción, vuelve a saltar tras la ejecución de la cláusula finally. También se ejecuta la cláusula finally ``a la salida'' si se abandona la sentencia try mediante break o return.

Una sentencia try debe tener una o más cláusulas except o una cláusula finally, pero no las dos.


Ver Sobre este documento... para obtener información sobre sugerencias.