Objetivo: Introducción al manejo de excepciones en Python.
Admítelo: los errores en tiempo de ejecución suceden. Tanto si intentas abrir un fichero inexistente como si tratas de utilizar un índice fuera del rango de una lista o string, por poner dos ejemplos comunes, la respuesta de Python siempre es desagradable. Si tienes suerte y estás trabajando desde el intérprete interactivo sólo recibirás el temido mensaje de error y podrás continuar. Pero si estás ejecutando un programa éste abortará inmediatamente.
Esto casi nunca es deseable. Imagina, por ejemplo, que tu aplicación facilita un servicio importante que requiere una disponibilidad de 24 horas. El daño ocasionado por tener tu programa parado podría ser importante (económico, reputación, imagen, etc.).
Puedes intentar aprender de los errores y modificar tu programa introduciendo líneas y líneas de código hasta hacerlo inexpugnable. Puede incluso que descubras que tienes más código escrito para tratar errores que código efectivo, lo que, en cierto modo sonaría un tanto ridículo.
Pero no hace falta que tu proyecto sea de envergadura para que te preocupes por gestionar adecuadamente los eventuales errores en tiempo de ejecución. Después de todo, si has elegido Python es porque eres una persona preocupada por la elegancia programando, de modo que tienes un compromiso contigo mismo.
Para lidiar con los errores en tiempo de ejecución Python dispone de mecanismos de gestión de excepciones.
Una excepción, en el mundo de la programación, no es más que una señal que lanza el programa advirtiendo que ha sucedido algo excepcional. Lo típico es un error en tiempo de ejecución pero, como descubriremos a lo largo de estos artículos, hasta tú mismo podrías lanzar tu propia señal de excepción de un modo creativo.
Ya conoces la respuesta de Python ante una excepción provocada por un error en tiempo de ejecución: pantallazo de error y el programa aborta. Pero, ¿y si pudiéramos modificar ese comportamiento por defecto a nuestro antojo, evitando así que el programa caiga?
Es lo que se conoce como capturar la excepción. Un ejemplo sencillo aclarará esto.
El error en tiempo de ejecución de libro típico es el intento de división entre cero, una cosa muy, muy mala, que puede hacer reventar tu sistema…
El siguiente programita pide, en un bucle infinito, que introduzcas dos números para dividirlos a continuación.
while True:
dividendo = int(input('Introduce el dividendo: '))
divisor = int(input('Introduce el divisor: '))
print('El cociente de la división de ambos números es', dividendo//divisor)
Vamos a jugar un poco con él:
Introduce el dividendo: 23
Introduce el divisor: 5
El cociente de la división de ambos números es 4
Introduce el dividendo: 12
Introduce el divisor: 7
El cociente de la división de ambos números es 1
Introduce el dividendo:
Todo bien, hasta ahora. Pero, ¿qué sucede si por divisor introducimos un cero?
Introduce el dividendo: 12
Introduce el divisor: 0
Traceback (most recent call last):
File "C:/Users/Javier/Desktop/borrable.py", line 4, in <module>
print('El cociente de la división de ambos números es', dividendo//divisor)
ZeroDivisionError: integer division or modulo by zero
Se acabó el programa abruptamente. Se ha producido un error en tiempo de ejecución ocasionado por intentar dividir entre cero, lo que ha ocasionado que se lanzara la excepción ZeroDivisionError, como nos muestra el texto del error.
Podríamos haber hecho daño al programa de más maneras. Observa cómo introducimos los valores con la función input(), que ya sabes que devuelve un string. Por eso recurrimos después a int() para convertir ese valor en un verdadero número entero con el que poder realizar operaciones aritméticas. Pero, ¿y si no podemos convertir lo introducido a entero porque no hemos facilitado un número?
Introduce el dividendo: casa
Traceback (most recent call last):
File "C:/Users/Javier/Desktop/borrable.py", line 2, in <module>
dividendo = int(input('Introduce el dividendo: '))
ValueError: invalid literal for int() with base 10: 'casa'
El programa aborta también, pero está vez devuelve un error diferente. Se ha producido una excepción del tipo ValueError.
Este comportamiento no es reprochable en Python, que desconoce el efecto que podría tener mantener el programa activo pese al error sucedido. Lo más prudente es informar de lo sucedido y abortar inmediatamente la ejecución, dejando al programador (tú), si lo desea, la captura de las excepciones.
Para capturar una excepción Python dispone de la estructura try/except. En la parte try incluimos el bloque de instrucciones que queremos proteger y en el except lo que queremos que se ejecute si sucede una excepción.
Vamos a proteger el código ante los dos eventuales errores que hemos descubierto que podrían sucedernos. Por un lado hay que proteger los input y por otro la línea con el resultado de la división, de modo que en bloque try incluimos las tres líneas críticas:
while True:
try:
dividendo = int(input('Introduce el dividendo: '))
divisor = int(input('Introduce el divisor: '))
print('El cociente de la división de ambos números es', dividendo//divisor)
except:
print('Eso no ha estado bien, pero no pasa nada')
print('Vuelve a intentarlo')
Presta mucha atención a la indentación, pues delimita, como siempre, la amplitud de los bloques en Python y permite saber a que try corresponde cada except.
Observa cómo, en la sección except, incluiremos código especial que sólo se ejecutará si se produce una excepción dentro del bloque protegido con try.
Vamos a verlo en acción:
Introduce el dividendo: 14
Introduce el divisor: 5
El cociente de la división de ambos números es 2
Introduce el dividendo: 35
Introduce el divisor: 0
Eso no ha estado bien, pero no pasa nada
Vuelve a intentarlo
Introduce el dividendo: 46
Introduce el divisor: casa
Eso no ha estado bien, pero no pasa nada
Vuelve a intentarlo
Introduce el dividendo: 12
Introduce el divisor: 5
El cociente de la división de ambos números es 2
Introduce el dividendo:
Ahora sí, a prueba de bombas. ¡Está protegido incluso ante un intento de interrupción con Ctrl-C! (excepción KeyboardInterrupt).
Esto ha sido sólo un aperitivo. En los sucesivos artículos sobre excepciones iremos refinando y ampliando estos conceptos, esperando los más sofisticados a que estemos en posesión previamente de ciertos conocimientos necesarios sobre las clases y la programación orientada a objetos. Todo a su momento.
Javier Montero Gabarró
El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)
El Club del Autodidacta
Consulta el índice completo de artículos relacionados con Python.
Estoy empezando en Python y tu blog me esta ayudando mucho, cada dia aprendo algo nuevo sobre este lenguaje. Gracias.
Me alegro de poder contribuir a tu formación.
¡Gracias!