Este tutorial explica el Manejo de Excepciones en Python usando el bloque Try Except con la ayuda de ejemplos de programación:
Hay dos tipos de error que pueden hacer que un programa Python se detenga bruscamente, a saber Errores de sintaxis y Excepciones En este tutorial, trataremos el segundo tipo de error (Excepciones) en varios temas importantes.
Nos beneficiaremos mucho del manejo de excepciones en nuestra aplicación como:
- Creación de una aplicación robusta.
- Creación de un código limpio y sin errores.
Python Try Excepto
Una buena noticia es que Python tiene un buen número de excepciones incorporadas para atrapar errores en nuestro código. Además, nos da la oportunidad de crear excepciones personalizadas cuando ninguna de las excepciones incorporadas se adapte a nuestras necesidades.
¿Qué es una excepción?
Entonces, ¿qué es una excepción en Python? Bueno, en términos simples, cada vez que el intérprete de Python intenta ejecutar código inválido, lanza una excepción, y en los casos en que dicha excepción no es manejada, interrumpe el flujo normal de las instrucciones del programa e imprime un traceback.
Creemos un código inválido y veamos cómo responderá el intérprete de Python.
Abra un intérprete de comandos Python y ejecute el siguiente código.
50/0
Este es uno de los errores más comunes en programación. El código anterior intenta dividir el número 50 por 0 (El intérprete de Python considera que se trata de una operación no válida y genera un error Error de división por cero interrumpe el programa e imprime un rastreo.
Podemos ver claramente que Error de división por cero es la excepción que se lanzó. De hecho, es la forma que tiene Python de decirnos que no está bien dividir un número por cero. Aunque en otros lenguajes como JavaScript, esto no es un error; y python prohíbe estrictamente esta práctica.
Además, es importante saber que esto es sólo un objeto de excepción y Python tiene muchos objetos de este tipo incorporados. Echa un vistazo a esta documentación oficial de Python para ver todas las excepciones incorporadas de Python.
Comprender el rastreo
Antes de adentrarnos en el manejo de excepciones, creo que será de ayuda entender qué ocurrirá exactamente si no se manejan las excepciones y cómo Python hace todo lo posible para informarnos de nuestro error.
Cada vez que Python encuentra un error, lanza una excepción. Si esta excepción no se maneja, entonces produce una información llamada Traceback. Entonces, ¿qué información contiene este traceback?
Contiene:
- El mensaje de error que nos indica qué excepción se ha producido y qué ha ocurrido antes de que se produjera esta excepción.
- Los distintos números de línea del código que ha causado este error. Un error puede estar causado por una secuencia de llamadas a funciones denominada llamar a la pila de la que hablaremos más adelante.
Aunque es un poco confuso, prometemos que el siguiente ejemplo aportará más luz a nuestra comprensión.
Recordemos el rastreo que se imprimió al dividir 50 entre 0 más arriba, podemos ver que el rastreo contiene la siguiente información:
- Archivo "": Esto nos indica que este código se ejecutó desde un terminal de consola.
- línea 1: Nos indica que el error se ha producido en este número de línea.
- ZeroDivisionError: división por cero: Nos dice qué excepción se planteó y qué la causó.
Probemos con otro ejemplo y veamos quizás cómo un llamar a la pila Abra un editor, introduzca el código siguiente y guárdelo como tracebackExp .py
def stack1(numb): # 1 div = 0 # 2 stack2(numb, div) # 3 def stack2(numb, div): # 5 compute = numb/div # 6 print(compute) # 7 if __name__ == '__main__': # 9 numb = 5 # 10 stack1(numb) # 11
Abra un terminal en el directorio donde se encuentra este archivo y ejecútelo.
python tracebackExp.py
Verá el siguiente rastreo:
El traceback anterior puede parecer confuso, pero en realidad no lo es. Los Pythonistas idearon la mejor forma de leer el traceback, que es desde el archivo de abajo arriba Así pues, utilicemos esta sabiduría para intentar comprender lo que ofrece este rastreo.
- En la parte inferior se indica la excepción que se ha producido y por qué.
- Subiendo, obtenemos el nombre del archivo tracebackExp .py donde ocurrió este error, el cálculo que causó este error compute = numb/div, la función stack2, y la línea 6 del número de enlace donde se realizó este cálculo.
- Moviéndonos hacia arriba, vemos que nuestra función stack2 fue llamada en la función stack1 en la línea número 3.
- Moviéndonos a la parte superior, vemos que la función stack1 fue llamada en la línea número 11. < módulo > nos indica que es el archivo que se está ejecutando.
Excepciones comunes de Python
La biblioteca de Python define una gran cantidad de excepciones incorporadas. Puede consultar la documentación de Python o llamar a la función incorporada local () como se indica a continuación:
dir(locals()['__builtins__'])
No trataremos de abordar todas estas excepciones, pero veremos algunas excepciones comunes con las que probablemente se encontrará.
#1) Error de tipo
Se produce cuando una operación o función se aplica a un objeto de un tipo inapropiado.
Ejemplo 1
Consideremos el siguiente programa, que toma un dividendo y un divisor, calcula e imprime el resultado de dividir el dividendo entre el divisor.
def compute_division(): dividend = int(input("Introduce el dividendo: ")) # convierte cadena a int divisor = input("Introduce el divisor: ") # sin conversión # calcula división resultado = dividendo/divisor # imprime resultado imprime("El resultado de {}/{} es: {}".format(dividendo, divisor, resultado)) if __name__ == '__main__': resultado = compute_division()
Solicitamos al usuario el valor del dividendo y del divisor, pero olvidamos convertir el valor de la cadena del divisor en un entero, por lo que el tipo del dividendo es integer( int ) y que el tipo del divisor sea string( str Obtenemos entonces el TypeError ya que el operador de división (/) no funciona con cadenas.
Quizás te interese saber que a diferencia de Python, Javascript tiene Coerción de Tipos que básicamente convierte uno de los tipos de los operandos a un valor equivalente del tipo del otro operando cuando los operandos son de tipos diferentes.
#2) ValueError
Se produce cuando una operación o función recibe un argumento que tiene el tipo correcto pero un valor inapropiado.
Ejemplo 2
Considere nuestro programa en Ejemplo 1 arriba.
Si el usuario introduce un valor alfanumérico para el dividendo como '3a', entonces nuestro programa lanzará la excepción ValueError. Esto se debe a que, aunque el método int() de Python acepta cualquier número o cadena y devuelve un objeto entero, el valor de la cadena no debe contener letras o cualquier valor no numérico.
#3) AtributoError
Esta excepción se produce al asignar o referenciar un atributo que no existe.
Ejemplo 3
Consideremos el siguiente programa, que toma un número y calcula su raíz cuadrada utilizando el módulo matemático de Python
import math # importar librería matemática para acceder a su código def calcular_raiz_cuadrada(número): # calcular la raíz cuadrada usando la librería matemática resultado = math.sqr(número) return resultado if __name__ == '__main__': # obtener la entrada para calcular del usuario número = int(entrada("Calcular raíz cuadrada de: ")) # llamar a la función para calcular la raíz cuadrada
Cuando un usuario introduce un número, nuestro programa intenta utilizar una función del módulo de matemáticas para calcular su raíz cuadrada pero justo aquí, cometimos un error. En lugar de sqrt, escribimos por error sqr que no existe en el módulo de matemáticas.
Por lo tanto, estábamos tratando de hacer referencia a un atributo sqr que no existe y dio lugar a la excepción AttributeError que se plantea. La mayoría de nosotros cometemos este tipo de error a menudo. Por lo tanto, usted no está solo.
Manejo de excepciones con Try Except
Como programador, una de las cosas a las que la mayoría de nosotros dedicamos nuestro tiempo es a escribir un código robusto que sea resistente. Código que no se rompa debido a algunos errores. En Python, podemos lograr esto encerrando nuestras sentencias dentro de una directiva pruebe - excepto declaración.
Sentencia Try-Except de Python
La sentencia try-except tiene la siguiente estructura:
try: #su código va aquí except """Especifique aquí tipo(s) de excepción""": #maneje aquí la excepción
Encerremos el código en tracebackExp .py dentro de una sentencia try-except.
def stack1(numb): # 1 div = 0 # 2 stack2(numb, div) # 3 def stack2(numb, div): # 5 try: # 6 compute = numb/div # 7 print(compute) # 8 except ZeroDivisionError as zde: # 9 print(zde) # 10 if __name__ == '__main__': # 12 numb = 5 # 13 stack1(numb) # 14 print("programa continuo") # 15
La ejecución de este código producirá el resultado
Así es como funciona la sentencia try-except. Python ejecuta el código en el bloque try líneas 7-8 Si no se encuentra ningún código inválido, entonces el código del bloque except línea 10 y la ejecución continúa.
Pero, si se encuentra un código inválido, entonces la ejecución se detiene inmediatamente en el bloque try y comprueba si la excepción lanzada coincide con la que proporcionamos en la sentencia except línea 9 Si coincide, el bloque except se ejecuta y continúa. Si no coincide, el programa se interrumpe.
El bloque try suele contener el código que puede lanzar una excepción, mientras que el bloque except la atrapa y la gestiona.
Manejo de múltiples excepciones con Except
Podemos manejar múltiples excepciones con un solo "except" o con múltiples "excepts". Todo depende de cómo quieras manejar cada excepción.
#1) Manejo de múltiples excepciones con una sola excepción
try: #tu código va aquí except(Excepción1[, Excepción2[,...ExcepciónN]]): #maneja la excepción aquí
Este método se utiliza cuando sospechamos que nuestro código puede lanzar diferentes excepciones y queremos tomar la misma acción en cada caso. Así, si el intérprete de Python encuentra una excepción, entonces se ejecutará el código escrito en el bloque except.
Veamos el siguiente ejemplo de código Python
def get_fraction(value, idx): arr = [4,5,2,0] # una lista de números idx_value = arr[idx] # si idx es> arr length, IndexError will be raised value/idx_value # si idx_value == 0, ZeroDivisionError will be raised if __name__ =='__main__': # set 'value' and 'idx' value = 54 idx = 3 # call function in a try-except statement. try: result = get_fraction(value, idx) print("La fracción es ", result) except(IndexError, ZeroDivisionError) as ex: print(ex)
Hay dos posibles excepciones que podrían plantearse aquí, Error de división por cero y Error de índice Si se produce alguna de estas excepciones, se ejecutará el bloque except.
En el código anterior, idx=3, por lo que idx_ valor se convierte en 0 y valor /idx_ valor se producirá ZeroDivisionError
#2) Manejo de múltiples excepciones con múltiples excepciones
try: #tu código va aquí except Excepción1: #manejar excepción1 aquí except Excepción2: #manejar excepción2 aquí except ExcepciónN: #manejar excepciónN aquí
Si preferimos manejar cada excepción por separado, así es como se puede hacer.
Considere el siguiente ejemplo de código Python
def get_fraction(value, idx): arr = [4,5,2,0] # una lista de números idx_value = arr[idx] # si idx es> arr length, IndexError will be raised value/idx_value # si idx_value == 0, ZeroDivisionError will be raised if __name__ =='__main__': # set 'value' and 'idx' value = 54 idx = 5 # call function in a try-excepts statement. try: result = get_fraction(value, idx) print("La fracción es ", result) exceptIndexError: print("idx de {} está fuera de rango".format(idx)) except ZeroDivisionError: print("arr[{}] es 0. Por lo tanto, no se puede dividir por cero".format(idx)) except Exception as ex: print(ex) print("No estoy seguro de lo que ha pasado, así que no es seguro continuar, la aplicación se interrumpirá") raise ex
Notamos aquí que Exception se usó en la última sentencia except. Esto se debe a que el objeto de excepción Exception coincide con cualquier excepción. Por esta razón, siempre debe ser el último, ya que Python dejará de comprobar otros manejadores de excepción una vez que uno coincida.
En el código anterior, idx=5 Por lo tanto arr[idx] aumentará Error de índice porque idx es mayor que la longitud de la lista arr
Además, no estar seguro de qué excepción fue lanzada por su aplicación nunca es seguro para continuar la ejecución. Es por eso que tenemos el tipo Exception para atrapar cualquier excepción no prevista. Luego, informamos al usuario e interrumpimos la aplicación lanzando la misma excepción.
Declaración Try Else
Se trata de un característica opcional de manejo de excepciones y le permite añadir código que desea ejecutar cuando no se produzcan errores. Si se produce un error, este else-block no se ejecutará.
Considera el ejemplo de código Python de abajo, abre tu editor y guarda el código como elseTry.py
def fraccion_de_uno(divisor): valor = 1/divisor # si el divisor es cero, se producirá un error ZeroDivisionError return valor if __name__ == '__main__': while True: try: # Obtener la entrada del usuario # si la entrada no es un argumento válido para int(), se producirá un error ValueError divisor = int(entrada("Introduce un divisor: ")) # llamar a nuestra función para calcular la fracción valor = fraccion_de_uno(divisor) except (ValueError,ZeroDivisionError): print("La entrada no puede ser cero y debería ser un literal válido para int(). Por favor, ¡inténtelo de nuevo!") else: print("Valor: ", valor) break
Obtenemos la entrada del usuario y la usamos para dividir 1. Tenemos dos posibles excepciones aquí, una entrada inválida del usuario que causará ErrorValor y un cero(0) que causará Error de división por cero Nuestra sentencia except se encarga de estos errores.
Ahora, queremos imprimir el valor de valor Nuestro bloque else se asegura de que se imprima sólo si nuestro bloque try se ejecuta sin error. Esto es importante porque si se produce un error en nuestro bloque try, el bloque valor estará sin definir, por lo que al acceder a él se producirá otro error.
Ejecuta el código anterior con Python elseTry.py
La salida anterior muestra que para la primera entrada, hemos escrito 0 y pulsamos ENTER. Como nuestro divisor recibió 0, 1/divisor subió zeroDivisionError Nuestra segunda entrada fue k, que no es válida para int (), de ahí la excepción ErrorValor se levanta.
Pero nuestra última entrada fue 9 que es válido y como resultado, obtuvimos el valor de " valor " impreso como 0.11111111111111111111
Pruebe por fin la declaración
También se trata de un característica opcional de manejo de excepciones y siempre se ejecutará sin importar lo que suceda en los manejadores de excepciones.
Eso es:
- Si se produce o no una excepción
- Incluso si se llama a un "retorno" en los otros bloques.
- Aunque se abandone el script en los otros bloques
Por lo tanto, si tenemos un código que queremos que se ejecute en todas las situaciones, el bloque finally es nuestro hombre. Este bloque se utiliza sobre todo para limpiezas como el cierre de archivos.
Considere el siguiente ejemplo de código Python
def readFile(file_path): try: openFile = open(file_path,'r') # Abrir un archivo como sólo lectura print(openFile.readline()) # Leer la primera línea del contenido del archivo except FileNotFoundError as ex: print(ex) finally: print("Limpiando...") openFile.close() if __name__ == '__main__': filePath = './text.txt' readFile(filePath)
Este código intenta abrir y leer el archivo text.txt en su directorio actual. Si el archivo existe, entonces nuestro programa imprimirá la primera línea del archivo y luego nuestro bloque finally se ejecutará y cerrará el archivo.
Digamos que tenemos un fichero llamado text.txt en el directorio donde está este fichero de programa y que contiene Hola. Si ejecutamos el programa, tendremos la salida
Este ejemplo fue elegido intencionalmente porque quería que tratáramos un pequeño problema que puede ocurrir al cerrar archivos en el bloque finally.
Si el fichero no existe, se produce la excepción FileNotFoundError y la variable openFile no estará definido y no será un objeto archivo, por lo que intentar cerrarlo en el bloque finally provocará una excepción UnboundLocalError que es una subclase de ErrorNombre .
Esto básicamente dice que estamos tratando de hacer referencia a la variable openFile antes de que se haya asignado.
Un pequeño truco es utilizar manejadores de excepciones dentro del bloque finally.
def readFile(file_path): try: openFile = open(file_path,'r') # Abre un archivo como sólo lectura print(openFile.readline()) # Lee la primera línea del contenido del archivo except FileNotFoundError as ex: print(ex) finally: try: print("Limpiando...") openFile.close() except: # atrapa todas las excepciones pass # Ignora este error porque no nos importa. if __name__ == '__main__': filePath = './text.txt' readFile(filePath)
Si nuestro bloque try genera un error FileNotFoundError, obtendremos el siguiente resultado
Crear excepción
Una buena noticia sobre las excepciones de Python es que podemos lanzarlas intencionadamente. Las excepciones se lanzan con el comando aumentar la declaración .
La sentencia raise tiene la siguiente sintaxis:
raise [NombreDeLaExcepción[(*args: Objeto)]]
Abre un terminal y lanza cualquier objeto de excepción de las excepciones incorporadas en Python. Por ejemplo, si lanzamos ZeroDivisionError:
>>> raise ErrorDivisiónCero("No se puede dividir por cero")
Obtendremos el rastreo:
Entonces, ¿por qué es importante plantear excepciones?
- Cuando se trabaja con excepciones personalizadas.
- Durante las comprobaciones de cordura.
Clases de excepción personalizadas
Una excepción personalizada es aquella que creas para manejar errores que son específicos de tu necesidad. El truco está en que definimos una clase que deriva del objeto Excepción entonces usamos la sentencia raise para lanzar nuestra clase de excepción.
Supongamos que queremos comprobar la entrada del usuario y asegurarnos de que el valor introducido no es negativo (comprobación de sanidad). Por supuesto, podríamos lanzar la excepción de Python ValueError pero nos gustaría personalizar el error dándole un nombre específico y autoexplicativo como InputIsNegativeError Pero esta excepción no es una excepción incorporada en Python.
Así que primero, creamos nuestra clase base que derivará de Exception.
class CustomError(Exception): "Excepción de clase base para todas las excepciones de este módulo" pass
Luego creamos nuestra clase de excepción que heredará la clase base y manejará nuestro error específico.
class InputIsNegativeError(CustomError): """Se produce cuando el usuario introduce un valor negativo"" pass
Probemos esto
try: value = int(input()) if value <0: raise InputIsNegativeError # Lanza una excepción si el valor es negativo except InputIsNegativeError: # atrapa y maneja la excepción print("El valor de entrada no debería ser negativo")
El código anterior solicita la entrada del usuario, y comprueba si es negativa. Si es cierto, lanza nuestra excepción personalizada InputIsNegativeError que es capturada posteriormente en la sentencia except.
A continuación se muestra el código completo:
class CustomError(Exception): "Clase de excepción base para todas las excepciones de este módulo" pass class InputIsNegativeError(CustomError): """Se produce cuando el usuario introduce un valor negativo""" pass if __name__ == '__main__': try: value = int(input("Introduce un número: ")) if value <0: raise InputIsNegativeError # Se produce una excepción si el valor es negativo except InputIsNegativeError: # catch and handle exceptionprint("El valor de entrada no debe ser negativo")
Si el valor de entrada es un número negativo como -1, entonces tendremos la salida:
Consulta la documentación de Python para más detalles sobre las excepciones personalizadas de Python.
Preguntas frecuentes
P #1) ¿Cómo maneja Python una excepción?
Contesta: Python gestiona las excepciones mediante la función sentencia try-except El código que puede provocar una excepción se coloca y ejecuta en el directorio bloque de prueba mientras que el excepto bloque contiene el código que gestionará las excepciones si se produce alguna.
P #2) ¿Qué es levantar una excepción en Python?
Contesta: Cada vez que el intérprete de Python encuentra un código inválido, lanza una excepción, que es la forma que tiene Python de decirnos que ha ocurrido algo inesperado. También podemos lanzar excepciones intencionadamente utilizando la función aumentar la declaración .
P #3) ¿Cómo maneja Python las excepciones múltiples?
Contesta: Python maneja múltiples excepciones utilizando un único bloque except o múltiples bloques except.
Para un solo bloque, las excepciones se pasan como una tupla: excepto (Excepción1, Excepción2,..,ExcepciónN) y Python busca una coincidencia de derecha a izquierda. En este caso, se realiza la misma acción para cada excepción.
Otra forma de capturar todas las excepciones es omitir el nombre de la excepción después de la palabra clave except.
except: # maneja todas las excepciones aquí
La segunda forma es utilizar un bloque except para cada excepción:
except Exception1: # el código para manejar Exception1 va aquí except Exception2: # el código para manejar Exception2 va aquí except ExceptionN: # el código para manejar ExceptionN va aquí
De este modo, puede tomar medidas separadas para cada excepción.
P #4) ¿Por qué es importante el manejo de excepciones en Python?
Contesta: El beneficio de manejar excepciones en Python es que podemos crear aplicaciones robustas, limpias y libres de errores. No querremos que nuestro código de producción se bloquee debido a algunos errores, así que manejamos los errores y mantenemos nuestra aplicación en funcionamiento.
P #5) ¿Cómo ignorar una excepción en Python?
Contesta: Para ignorar una excepción en Python, utilice el método pase en el bloque except. Digamos que queremos ignorar la excepción ValueError. Lo haremos de la siguiente manera:
except ValueError: pass
A menos que sepa lo que está haciendo, es una mala práctica ignorar las excepciones. Al menos, informe al usuario de todos los errores potenciales.
Conclusión
En este tutorial, cubrimos: Excepciones de Python, Traceback; cómo manejar excepciones con Pruebe / Excepto / Si no / Por último bloques, cómo Subir Exceptions, y finalmente cómo crear nuestras propias Custom Exceptions.
Gracias por leerme.