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 raise
es 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 try
y 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.
留言
張貼留言