Manejo de errores y excepciones Python (2)

Manejo de errores y excepciones Python (2)

Anteriormente, hablamos sobre el proceso de programación de Python, usando la declaración de prueba en el lugar donde puede ocurrir la excepción, para manejar correctamente algunas excepciones, para asegurar que el programa continúe ejecutándose sin interrupción.

Lanzar una excepción

A veces, es posible que tengamos que lanzar activamente una excepción en alguna parte del programa, notificando al programa que llamó al código que se ha producido un error.En este momento, vamos a utilizar la declaración de raise . raise declaración de raisees para ayudarnos a eliminar la excepción, como por ejemplo:
In [6]: raise NameError("Bad Name")
-----------------------------------
NameError           Traceback (most recent call last)
<ipython-input-6-966a00c8f456> in <module>
----> 1 raise NameError("Bad Name")

NameError: Bad Name
El uso de raise es muy simple, su sintaxis es la siguiente:
raise [expression [from expression]]
Si no tiene una expresión (parámetro) después de él, reiniciará la última excepción activa en el alcance actual. Si no hay una excepción activa en el alcance actual, se generará un RuntimeError para indicar el error.
Si le sigue una expresión, evalúe la expresión del objeto de excepción para lanzar, que debe ser una instancia de excepción o una clase de excepción (heredada de la clase BaseException ). Si es una clase de excepción, se creará una instancia implícita al llamar a un constructor sin argumentos:
raise NameError  # Equivalente a 'raise NameError()'
raise expresión de raise también puede ir seguida de una cláusula from para la concatenación de excepciones. La expresión de la cláusula from debe ser otra excepción o instancia que esté asociada con la excepción lanzada como un atributo __cause__grabable. Si la excepción lanzada no es atrapada, ambas excepciones serán impresas:
In [9]: try: 
   ...:     print(10/0) 
   ...: except Exception as e: 
   ...:     raise RuntimeError("something is wrong") from e 
   ...:
----------------------------------------------------------
ZeroDivisionError            Traceback (most recent call last)
<ipython-input-9-7de64aad634f> in <module>
      1 try:
----> 2     print(10/0)
      3 except Exception as e:

ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

RuntimeError                 Traceback (most recent call last)
<ipython-input-9-7de64aad634f> in <module>
      2     print(10/0)
      3 except Exception as e:
----> 4     raise RuntimeError("something is wrong") from e
      5 

RuntimeError: something is wrong
Si se lanza una except en una cláusula de except o en una cláusula finally , un mecanismo similar funcionará implícitamente, y la excepción anterior se asociará con el atributo __context__ de la nueva excepción. Por ejemplo:
In [10]: try: 
    ...:     print(10/0) 
    ...: except: 
    ...:     raise RuntimeError("something is wrong") 
    ...:
-----------------------------------------------
ZeroDivisionError           Traceback (most recent call last)
<ipython-input-10-e950a6292482> in <module>
      1 try:
----> 2     print(10/0)
      3 except:

ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

RuntimeError                Traceback (most recent call last)
<ipython-input-10-e950a6292482> in <module>
      2     print(10/0)
      3 except:
----> 4     raise RuntimeError("something is wrong")
      5 

RuntimeError: something is wrong
La concatenación excepcional se puede deshabilitar explícitamente mediante el uso de None en la cláusula from :
In [11]: try: 
    ...:     print(10/0) 
    ...: except: 
    ...:     raise RuntimeError("something is wrong") from None 
    ...:
-------------------------------
RuntimeError                   Traceback (most recent call last)
<ipython-input-11-1818bd8b9d31> in <module>
      2     print(10/0)
      3 except:
----> 4     raise RuntimeError("something is wrong") from None
      5 

RuntimeError: something is wrong

Excepción definida por el usuario

Python permite a los usuarios personalizar las clases de excepción, que normalmente deberían heredar directa o indirectamente de la clase de Exception .
El nombre de una clase de excepción personalizada generalmente termina con "Error", similar al nombre de la excepción estándar incorporada. Las clases de excepción personalizadas pueden realizar cualquier operación como otras clases, pero por lo general se mantienen simples, y solo proporcionan las propiedades que el controlador utiliza para extraer información de errores para las excepciones. Cuando se personalizan varias excepciones para diferentes errores para un módulo, es común definir una clase base de excepción para el módulo y luego crear una subclase específica para diferentes errores. Por ejemplo:
class ModuleError(Exception):
    '''Clase base de excepción del módulo'''
    pass


class ModuleNameError(ModuleError):
    '''Subclase de excepción específica del módulo.'''
    pass


class ModuleValueError(ModuleError):
    '''Otra subclase de excepción específica del módulo.'''
    pass

Limpieza final: cláusula final

finally cláusula finally es una cláusula opcional de la instrucción try que define la operación que se realiza en cualquier circunstancia, llamada "operación de limpieza". Por ejemplo:
In [12]: try: 
    ...:     raise NameError 
    ...: finally: 
    ...:     print('Bye :)') 
    ...:      
    ...:
Bye :)
-------------------------------
NameError        Traceback (most recent call last)
<ipython-input-12-9cda1523ce81> in <module>
      1 try:
----> 2     raise NameError
      3 finally:
      4     print('Bye :)')
      5 

NameError: 
finally cláusula finally siempre se ejecuta antes de abandonar la instrucción try , ya sea que ocurra una excepción o no. Cuando ocurre una excepción en la cláusula de tryy no ha sido procesada por la cláusula de except (o ocurre en la cláusula de excepción o de lo contrario), la excepción se volverá a lanzar después de que se ejecute la cláusula finally. Cuando cualquier otra cláusula de la declaración de prueba sale con una instrucción de interrupción, continuación o devolución, finalmente también se ejecuta antes de "antes de salir", consulte el ejemplo más complicado a continuación:
In [13]: def divide(a, b): 
    ...:     try: 
    ...:         result = a / b 
    ...:     except ZeroDivisionError: 
    ...:         print('divided by zero!') 
    ...:     else: 
    ...:         print('result is', result) 
    ...:     finally: 
    ...:         print('leaving try') 
    ...:

In [14]: divide(8, 2)
result is 4.0
leaving try

In [15]: divide(8, 0)
divided by zero!
leaving try

In [16]: divide('a', 2)
leaving try
-----------------------
TypeError              Traceback (most recent call last)
<ipython-input-16-324d9fa22da2> in <module>
----> 1 divide('a', 2)

<ipython-input-13-5e4380c62566> in divide(a, b)
      1 def divide(a, b):
      2     try:
----> 3         result = a / b
      4     except ZeroDivisionError:
      5         print('divided by zero!')

TypeError: unsupported operand type(s) for /: 'str' and 'int'
Del ejemplo anterior, vemos que la cláusula finally siempre será ejecutada. Sin embargo, cuando se elimina la cadena, se lanza una excepción TypeError . Esta excepción no es manejada por la cláusula de except y se volverá a lanzar después de que se ejecute la cláusula finally .
En la práctica de programación, la cláusula finally es muy útil para liberar recursos externos, como archivos o conexiones de red.

Resumen

En la programación, no solo necesitamos manejar las excepciones en el lugar correcto, sino también lanzar las excepciones cuando sea necesario. Podemos personalizar las excepciones cuando lanzamos las excepciones. El uso experto de las excepciones puede hacer que nuestros programas sean más sólidos, y no se olvide de utilizar finally para liberar recursos externos cuando sea necesario.

留言