86 - Instrucción finally en un bloque try

Ver video

Hemos visto que la sintaxis para la captura de excepciones es:

try:
    [algoritmo principal]
except [nombre de la excepción 1]:
    [algoritmo alternativo 1]
except [nombre de la excepción 2]:
    [algoritmo alternativo 2]
except [nombre de la excepción 3]:
    [algoritmo alternativo 3]

Hay otra sección opcional de la cláusula 'try' llamada 'finally':

try:
    [algoritmo principal]
except [nombre de la excepción 1]:
    [algoritmo alternativo 1]
except [nombre de la excepción 2]:
    [algoritmo alternativo 2]
except [nombre de la excepción 3]:
    [algoritmo alternativo 3]
finally:
    [algoritmo que siempre se ejecuta]

Cuando en el algoritmo principal se genera una excepción las instrucciones que continúan nunca se ejecutarán ya que pasa a ejecutar el bloque del 'except'. Hay situaciones donde queremos que haya un algoritmo que siempre se ejecute ya sea que se dispare una excepción o no.

Veamos algunos ejemplos donde es conveniente emplear el bloque finally.

Problema:

Almacenar una serie de string en un archivo de texto. Tratar de llamar al método 'write' pasando un entero.

Programa: ejercicio301.py

try:
    archi1=open("datos.txt","w") 
    archi1.write("Primer línea.\n") 
    archi1.write("Segunda línea.\n") 
    archi1.write("Tercer línea.\n")  
    archi1.write(3334)
except TypeError:
    print("No se puede grabar un entero con write")    
finally:
    archi1.close() 
    print("Se cerró el archivo")

Si ejecutamos este programa al llamar al método write con un dato entero se genera la excepción 'TypeError':

    archi1.write(3334)
except TypeError:
    print("No se puede grabar un entero con write")    

try finally de python

Luego de capturarse la excepción 'TypeError' se ejecuta el bloque 'finally' donde se cierra el archivo:

finally:
    archi1.close() 
    print("Se cerró el archivo")

Si modificamos el programa y borramos la línea donde grabamos el entero no se capturan excepciones pero si se ejecuta el bloque 'finally' donde se cierra el archivo.

Si no existiera la instrucción finally nuestro programa quedaría:

try:
    archi1=open("datos.txt","w") 
    archi1.write("Primer línea.\n") 
    archi1.write("Segunda línea.\n") 
    archi1.write("Tercer línea.\n")  
    archi1.write(3334)
    archi1.close() 
    print("Se cerró el archivo")    
except TypeError:
    print("No se puede grabar un entero con write")    

De esta forma el algoritmo tiene el problema que nunca cerrará el archivo ya que no se ejecutará el bloque:

    archi1.close() 
    print("Se cerró el archivo")    

Es muy común utilizar la cláusula 'finally' para liberar recursos solicitados dentro del bloque 'try'. Veamos con otro ejemplo ya resuelto anteriormente accediendo a una base de datos de MySQL.

Problema:

Conectarse a una base de datos de MySQL y ejecutar un comando SQL incorrecto.

Programa: ejercicio302.py

import mysql.connector

try:
    conexion1=mysql.connector.connect(host="localhost", user="root", passwd="")
    cursor1=conexion1.cursor()
    cursor1.execute("show databasesqqqqqqqq")
    for base in cursor1:
        print(base)
except mysql.connector.errors.ProgrammingError:
    print("Error en el comando SQL")        
finally:        
    conexion1.close()
    print("Se cerró la conexión a la base de datos")

Hemos definido un comando SQL incorrecto al llamar al método 'execute':

    cursor1.execute("show databasesqqqqqqqq")

Luego se captura la excepción 'ProgrammingError' que se encuentra en el módulo 'mysql.connector.errors':

except mysql.connector.errors.ProgrammingError:
    print("Error en el comando SQL")        

Indistintamente que dispongamos un comando SQL correcto o incorrecto luego se ejecuta el bloque finally donde cerramos la conexión:

finally:        
    conexion1.close()
    print("Se cerró la conexión a la base de datos")