La forma por defecto que tiene Python de manejar errores no está tan mal para un programador, pero es bastante brutal para un usuario. Detenerse bruscamente con un mensaje de error en inglés que muchas veces no entienden ni los que hablan inglés, es algo que puede mejorarse.
Funcionando en 5 minutos
El siguiente esquema es la forma más básica de manejar errores, que se puede tener funcionando en 5 minutos o menos:
numero = 10
numero += 1
salida = f"El resultado es {numero} unidades."
print(salida)
if numero == 11:
print("Al final era 11")
else:
print("Veo que no era 11")
except Exception:
print("Ocurrió un error")
else:
print("No hubo errores")
finally:
print("Finalizando ordenadamente")
Explicación práctica
Esta explicación es suficiente para empezar ya mismo con el control de errores.
Las 4 palabras en naranja dividen el código en 4 partes bien concretas.
Estas 4 partes se aplican sobre una porción determinada del código que puede ser la más compleja o la más crítica.
No es necesario controlar todo el archivo de código fuente (.py)
Tampoco se limita a una sola porción del código. Esta estructura puede usarse en distintas partes del mismo archivo.
Si hay una parte del código cuyos errores deseemos tener controlados, ya es un buen motivo para usarla.
try:
A continuación de try: se coloca el código cuyos errores queremos capturar.
except:
Recordemos que esta es la forma más básica, por lo tanto usamos una sola vez except: La palabra que sigue es el nombre de la clase de error que queremos controlar. Exception es la clase general, así que irá bien con cualquier error.
Debajo de except: va el código que queremos ejecutar si se produce un error.
else:
Debajo de else: va el código que queremos ejecutar si no hubo ningún error. Es opcional.
finally:
Debajo de finally: va el código que queremos ejecutar siempre, como cierre del try: Es decir, haya o no error se ejecutará.
En acción
En este punto sería bueno copiar el código de arriba, pegarlo en VS Code o el editor que usen, y modificarlo para que ocurran errores.
Por ejemplo:
- Probar sin modificar nada, para ver cómo funciona sin errores.
- Antes del try:, hacer que divisor valga 0. Ocurrirá un error de división por 0. Como está fuera del try:, no se controlará.
- Luego del try:, cambiar el nombre de alguna variable o introducir alguna otro error.
Explicación teórica (pero liviana)
Excepciones
Lo que hacemos con esto se llama "capturar excepciones".
Las excepciones se producen cuando ocurre un error mientras el programa está funcionando.
Una excepción es en rigor un objeto, derivado de la clase BaseException.
Este objeto contiene información sobre un error.
Si se van a crear nuevas excepciones, no deben derivarse de BaseException sino de Exception, o incluso de subclases de ésta.
Hay clases estándar que, desde luego, derivan de Exception.
Debajo de except: se escribe el código que se va a ejecutar cuando ocurra un error de la clase que se indica luego de except.
Veamos: si el error es de tipo de datos (multiplicar dos string por ejemplo), la excepción generada será un objeto de la clase TypeError (se maneja con código que se escribe debajo de except TypeError:)
Si el error es de división por cero, la excepción generada será un objeto de la clase ZeroDivisionError (se maneja con código que se escribe debajo de except ZeroDivisionError:)
Los errores más toscos y fáciles de descubrir son los de sintaxis. (clase SyntaxError, se captura con except SyntaxError:) Por ejemplo, escribir primt en lugar de print. Esos errores no cambian. Desde que se tipeó mal ya existen y no se irán hasta que se corrija la escritura. Es más, VS Code los detecta instantáneamente.
Hay otros errores que pueden ocurrir o no. Por ejemplo:
Si en este programa el usuario introduce algo distinto a 0 cuando se le pide el divisor, funcionará bien, pero si ingresa 0 se va a producir un error de división por 0.
Es decir, es un error que al momento de hacer el programa no se sabe si ocurrirá o no.
Tratamiento de errores
Como explico en esta historia, tenemos dos maneras diferentes de enfrentar los errores que no se sabe cuándo podrían suceder:
LBYL (Look Before You Leap, o mire antes de saltar) significa que vamos a validar todo lo que se pueda. Por ejemplo, controlar que divisor no sea 0 y si lo es, emitir un mensaje y volver a pedirlo.
LBYL se ve robusto pero se gasta bastante tiempo y energía (y líneas de código) en evaluar que los datos sean correctos y las distintas condiciones estén dadas (por ejemplo, que haya espacio en disco antes de copiar un archivo)
EAFP (Easier to ask for forgiveness than permission, o es más fácil pedir perdón que permiso) significa en forma muy simple que vamos a programar como si nada malo pudiese ocurrir, pero atención: usando try-except para capturar los errores que ocurran.
EAFP me agrada bastante porque en última instancia no se le pasa por alto ningún error. La cláusula except: puede usarse (como vimos arriba) con la clase Exception, lo que no dejará pasar ningún error, pero pueden usarse varios except: para detectar distintas clases de error y hacer el tratamiento más eficiente.
¿Y finally:? ¿Sirve o no sirve?
Al programador principiante puede parecerle un tanto inútil finally.
Pero el experimentado sabe que un programa empieza a hacer muchas cosas que luego debería terminar, haya o no haya un error.
Un caso típico es la escritura en archivos.
En pocas palabras, si se abre un archivo con intención de agregarle datos, luego hay que cerrarlo. Si esa operación, por ser crítica se encierra en un try:, el mejor lugar para cerrar el archivo es justamente finally:
Como finally: se ejecuta siempre, la finalizacion perfecta para un intento de escribir en un archivo (si se controló con try:) es cerrarlo en esa parte.
Como criterio general, finally: contiene código que pone todo en orden luego de la tarea supervisada con try: Según el caso puede ser destruir objetos o variables, o reinicializarlos (volverlos al valor por defecto), cerrar archivos, enviar un mensaje, etc. etc. etc.
Explicación teórica avanzada (pero útil)
Ya mostré como usar try: en 5 minutos y expliqué un poco de teoría básica.
Ahora planeo tocar temas puntuales que mejorarán tu aprovechamiento de try-except
try anidados
Los try: pueden anidarse.
Esto significa que el código que se pone entre try: y except; puede tener a su vez una parte que se controle con otro try: para capturar sus propios errores.
linea 1
linea 4
except TypeError:
print("Ocurrió un error en lineas 4-6")
else:
print("No hubo errores en lineas 4-6")
finally:
print("Finalizando ordenadamente lineas 4-6")
except Exception:
print("Ocurrió un error en lineas 1-6")
else:
print("No hubo errores en lineas 1-6")
finally:
print("Finalizando ordenadamente lineas 1-6")
En el código de arriba se ve que las lineas 1, 2 y 3 están contenidas por un try:, pero las líneas 4, 5 y 6 están a su vez dentro de otro try:
Una característica de los try: anidados:
Si el except: del try: más interno no pudiera gestionar el error (notar que hace referencia a errores de tipo) el control se va a pasar al try: exterior. Que en este ejemplo sí lo gestionaría porque hace referencia a Exception
Gestionar varios tipos de errores en un solo except:
Dijimos que los errores generan excepciones, que las excepciones son objetos, que como todo objeto tienen una clase, y que para indicar el código que las manejará debemos indicar except <clase>:
Bien, si estuvieran en el caso de que un mismo código sirve para 2 o más clases de excepciones, pueden indicar todas juntas colocándolas dentro de una tupla
En Python una tupla es una lista entre paréntesis.
Ejemplo:
try:
except (EOFError, MemoryError, IOError):
A primera vista parecería que le pasamos 3 argumentos entre paréntesis a except, pero no. No es una función. Lo que se le está pasando es una tupla con 3 elementos. Así "empaquetamos" y pasamos a except las clases que queremos gestionar con el código que seguirá.
Obtener información sobre el error
Por la clase de excepción que "disparó" el except: donde entró el programa ya tenemos idea de lo que causó el error, pero si usamos la muy general clase Exception o simplemente necesitamos más datos, esta es la forma de conseguirlos:
(---)
Biblio:
https://docs.python.org/3/reference/compound_stmts.html#try
https://ellibrodepython.com/excepciones-try-except-finally
https://docs.python.org/3/library/exceptions.html
https://ellibrodepython.com/definir-excepcion
https://docs.python.org/es/3.13/tutorial/errors.html
https://nipotticlaudio.blogspot.com/2024/04/es-mas-facil-pedir-perdon-que-permiso.html
https://docs.python.org/es/3/library/exceptions.html


