Excepciones en Python y como usarlas: try, except, finally y raise

Excepciones en Python

Las excepciones en Python son una herramienta muy potente que la gran mayor铆a de lenguajes de programaci贸n modernos tienen. Se trata de una forma de controlar el comportamiento de un programa cuando se produce un error.

Esto es muy importante ya que salvo que tratemos este error, el programa se parar谩, y esto es algo que en determinadas aplicaciones no es una opci贸n v谩lida.

Imaginemos que tenemos el siguiente c贸digo con dos variables a y b y realizamos su divisi贸n a/b.

a = 4
b = 2
c = a/b

Pero imaginemos ahora que por cualquier motivo las variables tienen otro valor, y que por ejemplo b tiene el valor 0. Si intentamos hacer la divisi贸n entre cero, este programa dar谩 un error y su ejecuci贸n terminar谩 de manera abrupta.

a = 4; b = 0
print(a/b)
# ZeroDivisionError: division by zero

Ese "error" que decimos que ha ocurrido es lanzado por Python (raise en Ingl茅s) ya que la divisi贸n entre cero es una operaci贸n que matem谩ticamente no est谩 definida.

Se trata de la excepci贸n ZeroDivisionError. En el siguiente enlace, tenemos un listado de todas las excepciones con las que nos podemos encontrar.

Veamos un ejemplo con otra excepci贸n. 驴Que pasar铆a si intent谩semos sumar un n煤mero con un texto? Evidentemente esto no tiene ning煤n sentido, y Python define una excepci贸n para esto llamada TypeError.

print(2 + "2")

En base a esto es muy importante controlar las excepciones, porque por muchas comprobaciones que realicemos es posible que en alg煤n momento ocurra una, y si no se hace nada el programa se parar谩.

驴Te imaginas que en un avi贸n, un tren o un cajero autom谩tico tiene un error que lanza raise una excepci贸n y se detiene por completo?

Una primera aproximaci贸n al control de excepciones podr铆a ser el siguiente ejemplo. Podemos realizar una comprobaci贸n manual de que no estamos dividiendo por cero, para as铆 evitar tener un error tipo ZeroDivisionError.

Sin embargo es complicado escribir c贸digo que contemple y que prevenga todo tipo de excepciones. Para ello, veremos m谩s adelante el uso de except.

a = 5
b = 0
# A trav茅s de esta comprobaci贸n prevenimos que se divida entre cero.
if b!=0:
    print(a/b)
else:
    print("No se puede dividir!")

Uso de raise

Tambi茅n podemos ser nosotros los que levantemos o lancemos una excepci贸n. Volviendo a los ejemplos usados en el apartado anterior, podemos ser nosotros los que levantemos ZeroDivisionError o NameError usando raise. La sintaxis es muy f谩cil.

raise ZeroDivisionError("Informaci贸n de la excepci贸n")

O podemos lanzar otra de tipo NameError.

raise NameError("Informaci贸n de la excepci贸n")

Se puede ver como el string que hemos pasado se imprime a continuaci贸n de la excepci贸n. Se puede llamar tambi茅n sin ning煤n par谩metro como se hace a continuaci贸n.

raise ZeroDivisionError

Visto esto, ya sabemos como una excepci贸n puede ser lanzada. Existen dos maneras principalmente:

  • Hacemos una operaci贸n que no puede ser realizada (como dividir por cero). En este caso Python se encarga de lanzar autom谩ticamente la excepci贸n.
  • O tambi茅n podemos lanzar nosotros una excepci贸n manualmente, usando raise.
  • Habr铆a un tercer caso que ser铆a lanzar una excepci贸n que no pertenece a las definidas por defecto en Python. Pero eso te lo explicamos aqu铆.

A continuaci贸n veremos que podemos hacer para controlar estas excepciones, y que hacer cuando se lanza una para que no se interrumpa la ejecuci贸n del programa.

Uso de try y except

La buena noticia es que las excepciones que hemos visto antes, pueden ser capturadas y manejadas adecuadamente, sin que el programa se detenga. Veamos un ejemplo con la divisi贸n entre cero.

a = 5; b = 0
try:
    c = a/b
except ZeroDivisionError:
    print("No se ha podido realizar la divisi贸n")

En este caso no verificamos que b!=0. Directamente intentamos realizar la divisi贸n y en el caso de que se lance la excepci贸n ZeroDivisionError, la capturamos y la tratamos adecuadamente.

La diferencia con el ejemplo anterior es que ahora no se para el programa y se puede seguir ejecutando. Prueba a ejecutar el c贸digo y ver que pasa. Ver谩s como el programa ya no se para.

Entonces, lo que hay dentro del try es la secci贸n del c贸digo que podr铆a lanzar la excepci贸n que se est谩 capturando en el except. Por lo tanto cuando ocurra una excepci贸n, se entra en el except pero el programa no se para.

Tambi茅n se puede capturar diferentes excepciones como se ve en el siguiente ejemplo.

try:
    #c = 5/0       # Si comentas esto entra en TypeError
    d = 2 + "Hola" # Si comentas esto entra en ZeroDivisionError
except ZeroDivisionError:
    print("No se puede dividir entre cero!")
except TypeError:
    print("Problema de tipos!")

Puedes tambi茅n hacer que un determinado n煤mero de excepciones se traten de la misma manera con el mismo bloque de c贸digo. Sin embargo suele ser m谩s interesante tratar a diferentes excepciones de diference manera.

try:
    #c = 5/0       # Si comentas esto entra en TypeError
    d = 2 + "Hola" # Si comentas esto entra en ZeroDivisionError
except (ZeroDivisionError, TypeError):
    print("Excepcion ZeroDivisionError/TypeError")

Otra forma si no sabes que excepci贸n puede saltar, puedes usar la clase gen茅rica Exception. En este caso se controla cualquier tipo de excepci贸n. De hecho todas las excepciones heredan de Exception. Ver documentaci贸n.

try:
    #c = 5/0       # Si comentas esto entra en TypeError
    d = 2 + "Hola" # Si comentas esto entra en ZeroDivisionError
except Exception:
    print("Ha habido una excepci贸n")

No obstante hay una forma de saber que excepci贸n ha sido la que ha ocurrido.

try:
    d = 2 + "Hola" # Si comentas esto entra en ZeroDivisionError
except Exception as ex:
    print("Ha habido una excepci贸n", type(ex))

# Ha habido una excepci贸n <class 'TypeError'>

Uso de else

Al ya explicado try y except le podemos a帽adir un bloque m谩s, el else. Dicho bloque se ejecutar谩 si no ha ocurrido ninguna excepci贸n. F铆jate en la diferencia entre los siguientes c贸digos.

try:
    # Forzamos una excepci贸n al dividir entre 0
    x = 2/0
except:
    print("Entra en except, ha ocurrido una excepci贸n")
else:
    print("Entra en else, no ha ocurrido ninguna excepci贸n")

#Entra en except, ha ocurrido una excepci贸n

Sin embargo en el siguiente c贸digo la divisi贸n se puede realizar sin problema, por lo que el bloque except no se ejecuta pero el else si es ejecutado.

try:
    # La divisi贸n puede realizarse sin problema
    x = 2/2
except:
    print("Entra en except, ha ocurrido una excepci贸n")
else:
    print("Entra en else, no ha ocurrido ninguna excepci贸n")

#Entra en else, no ha ocurrido ninguna excepci贸n

Uso de finally

A los ya vistos bloques try, except y else podemos a帽adir un bloque m谩s, el finally. Dicho bloque se ejecuta siempre, haya o no haya habido excepci贸n.

Este bloque se suele usar si queremos ejecutar alg煤n tipo de acci贸n de limpieza. Si por ejemplo estamos escribiendo datos en un fichero pero ocurre una excepci贸n, tal vez queramos borrar el contenido que hemos escrito con anterioridad, para no dejar datos inconsistenes en el fichero.

En el siguiente c贸digo vemos un ejemplo. Haya o no haya excepci贸n el c贸digo que haya dentro de finally ser谩 ejecutado.

try:
    # Forzamos excepci贸n
    x = 2/0
except:
    # Se entra ya que ha habido una excepci贸n
    print("Entra en except, ha ocurrido una excepci贸n")
finally:
    # Tambi茅n entra porque finally es ejecutado siempre
    print("Entra en finally, se ejecuta el bloque finally")

#Entra en except, ha ocurrido una excepci贸n
#Entra en finally, se ejecuta el bloque finally

Ejemplos

Un ejemplo muy t铆pico de excepciones es en el manejo de ficheros. Se intenta abrir, pero se captura una posible excepci贸n. De hecho si entras en la documentaci贸n de open se indica que OSError es lanzada si el fichero no puede ser abierto.

#聽Se intenta abrir un fichero y se captura una posible excepci贸n
try:
    with open('fichero.txt') as file:
        read_data = file.read()
except:
    # Se entra aqu铆 si no pudo ser abierto
    print('No se pudo abrir')

Como ya hemos comentado, en el except tambi茅n se puede capturar una excepci贸n concreta. Dependiendo de nuestro programa, tal vez queramos tratar de manera distinta diferentes tipos de excepciones, por lo que es una buena pr谩ctica especificar que tipo de excepci贸n estamos tratando.

#聽Se intenta abrir un fichero y se captura una posible excepci贸n
try:
    with open('fichero.txt') as file:
        read_data = file.read()
# Capturamos una excepci贸n concreta
except OSError:
    print('OSError. No se pudo abrir')

En este otro ejemplo vemos el uso de los bloques try, except, else y finally todos juntos.

try:
    # Se fuerza excepci贸n
    x = 2/0
except:
    print("Entra en except, ha ocurrido una excepci贸n")
else:
    print("Entra en el else, no ha ocurrido ninguna excepci贸n")
finally:
    print("Entra en finally, se ejecuta el bloque finally")

Tambi茅n se puede capturar una excepci贸n de tipo SyntaxError, que hace referencia a errores de sintaxis. Sin embargo el c贸digo deber铆a estar libre de este tipo de fallos, por lo que tal vez nunca deber铆as usar esto.

try:
    print("Hola"))
except SyntaxError:
    print("Hay un error de sintaxis")

¡Deja un comentario!

avatar
  Subscribe  
Notify of