propias - que es try en python
Levantando(lanzando) manualmente una excepción en Python (5)
¿Cómo lanzo / levanto manualmente una excepción en Python?
Utilice el constructor de excepciones más específico que se adapta semánticamente a su problema .
Sea específico en su mensaje, por ejemplo:
raise ValueError(''A very specific bad thing happened.'')
No levante excepciones genéricas
Evite elevar una excepción genérica. Para atraparlo, deberás capturar todas las demás excepciones más específicas que la subclase.
Problema 1: Ocultando errores
raise Exception(''I know Python!'') # Don''t! If you catch, likely to hide bugs.
Por ejemplo:
def demo_bad_catch():
try:
raise ValueError(''Represents a hidden bug, do not catch this'')
raise Exception(''This is the exception you expect to handle'')
except Exception as error:
print(''Caught this error: '' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError(''Represents a hidden bug, do not catch this'',)
Problema 2: No atrapará
y las capturas más específicas no captarán la excepción general:
def demo_no_catch():
try:
raise Exception(''general exceptions not caught by specific handling'')
except ValueError as e:
print(''we will not catch exception: Exception'')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
Buenas Prácticas: raise
declaración
raise ValueError(''A very specific bad thing happened'')
lo que también permite fácilmente pasar un número arbitrario de argumentos al constructor:
raise ValueError(''A very specific bad thing happened'', ''foo'', ''bar'', ''baz'')
A estos argumentos se accede mediante el atributo args
en el objeto Exception. Por ejemplo:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
huellas dactilares
(''message'', ''foo'', ''bar'', ''baz'')
En Python 2.5, se agregó un atributo de message
real a BaseException a favor de alentar a los usuarios a que hagan excepciones en la subclase y dejen de usar args
, pero la introducción del message
y la desestimación original de args se han retraído .
Buenas prácticas: except
cláusula
Cuando se encuentra dentro de una cláusula de excepción, es posible que desee, por ejemplo, registrar que ocurrió un tipo específico de error y luego volver a aumentar. La mejor manera de hacer esto mientras se conserva el seguimiento de la pila es usar una declaración de aumento desnudo. Por ejemplo:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don''t do this, you''ll lose the stack trace!
No modifiques tus errores ... pero si insistes.
Puede conservar el seguimiento de pila (y el valor de error) con sys.exc_info()
, pero esto es mucho más propenso a errores y tiene problemas de compatibilidad entre Python 2 y 3 , prefiero usar una raise
simple para volver a subir.
Para explicar: el sys.exc_info()
devuelve el tipo, el valor y el rastreo.
type, value, traceback = sys.exc_info()
Esta es la sintaxis en Python 2; tenga en cuenta que esto no es compatible con Python 3:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
Si lo desea, puede modificar lo que sucede con su nuevo aumento, por ejemplo, establecer nuevos argumentos para la instancia:
def error():
raise ValueError(''oops!'')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + '' <modification>'',)
raise error_type, error_instance, traceback
Y hemos conservado todo el rastreo mientras modificamos los argumentos. Tenga en cuenta que esta no es una buena práctica y que la sintaxis no es válida en Python 3 (lo que hace que la compatibilidad sea mucho más difícil de solucionar).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
En Python 3 :
raise error.with_traceback(sys.exc_info()[2])
De nuevo: evita manipular manualmente las trazas. Es menos eficiente y más propenso a errores. Y si está usando subprocesos y sys.exc_info
, puede incluso obtener el sys.exc_info
incorrecto (especialmente si está utilizando el manejo de excepciones para el flujo de control, lo que personalmente tiendo a evitar).
Python 3, encadenamiento de excepciones
En Python 3, puede encadenar excepciones, que conservan las trazas de retorno:
raise RuntimeError(''specific message'') from error
Estar atentos
- esto permite cambiar el tipo de error generado, y
- Esto no es compatible con Python 2.
Métodos en desuso:
Estos pueden ocultar fácilmente e incluso entrar en el código de producción. Desea generar una excepción, y hacerlas generará una excepción, ¡ pero no la prevista!
Válido en Python 2, pero no en Python 3 es el siguiente:
raise ValueError, ''message'' # Don''t do this, it''s deprecated!
Solo válido en versiones mucho más antiguas de Python (2.4 y versiones inferiores), es posible que aún veas personas que suben cadenas:
raise ''message'' # really really wrong. don''t do this.
En todas las versiones modernas, esto generará un TypeError, ya que no está generando un tipo BaseException. Si no está buscando la excepción correcta y no tiene un revisor que esté al tanto del problema, podría entrar en producción.
Ejemplo de uso
Aumento de excepciones para advertir a los consumidores de mi API si la usan de forma incorrecta:
def api_func(foo):
''''''foo should be either ''baz'' or ''bar''. returns something very useful.''''''
if foo not in _ALLOWED_ARGS:
raise ValueError(''{foo} wrong, use "baz" or "bar"''.format(foo=repr(foo)))
Crea tus propios tipos de error cuando te convenga.
"Quiero cometer un error a propósito, para que entre en la excepción"
Puede crear sus propios tipos de error, si desea indicar que algo específico está mal con su aplicación, simplemente haga una subclase del punto apropiado en la jerarquía de excepciones:
class MyAppLookupError(LookupError):
''''''raise this when there''s a lookup error for my app''''''
y uso:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError(''resource is missing, and that is not ok.'')
¿Cómo puedo generar una excepción en Python para que luego pueda detectarse mediante un bloque de except
?
NO HAGAS ESTO . Elevar una
Exception
desnuda no es absolutamente lo correcto; ver share lugar.
No se puede obtener mucho más pitón que esto:
raise Exception("I know python!")
Consulte los documentos de declaración de subida para python si desea obtener más información.
En Python3 hay 4 sintaxis diferentes para las excepciones de rasing:
1. raise exception
2. raise exception (args)
3. raise
4. raise exception (args) from original_exception
1. aumentar excepción vs. 2. aumentar excepción (args)
Si usa la raise exception (args)
para generar una excepción, los args
se imprimirán cuando imprima el objeto de excepción, como se muestra en el siguiente ejemplo.
#raise exception (args)
try:
raise ValueError("I have raised an Exception")
except ValueError as exp:
print ("Error", exp) # Output -> Error I have raised an Exception
#raise execption
try:
raise ValueError
except ValueError as exp:
print ("Error", exp) # Output -> Error
3. risa
raise
declaración sin ningún argumento re-plantea la última excepción. Esto es útil si necesita realizar algunas acciones después de capturar la excepción y luego desea volver a elevarla. Pero si no hubo una excepción antes, la declaración de raise
genera una excepción de TypeError
.
def somefunction():
print("some cleaning")
a=10
b=0
result=None
try:
result=a/b
print(result)
except Exception: #Output ->
somefunction() #some cleaning
raise #Traceback (most recent call last):
#File "python", line 8, in <module>
#ZeroDivisionError: division by zero
4. generar excepción (args) de original_exception
Esta declaración se utiliza para crear un encadenamiento de excepciones en el que una excepción que se produce en respuesta a otra excepción puede contener los detalles de la excepción original, como se muestra en el siguiente ejemplo.
class MyCustomException(Exception):
pass
a=10
b=0
reuslt=None
try:
try:
result=a/b
except ZeroDivisionError as exp:
print("ZeroDivisionError -- ",exp)
raise MyCustomException("Zero Division ") from exp
except MyCustomException as exp:
print("MyException",exp)
print(exp.__cause__)
Salida:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
Para el caso común en el que necesita lanzar una excepción en respuesta a algunas condiciones inesperadas, y que nunca tiene la intención de atrapar, sino simplemente fallar rápidamente para permitirle depurar desde allí si alguna vez sucede, el más lógico parece ser AssertionError
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of ''distance''!", distance)
Lea primero las respuestas existentes, esto es solo un apéndice.
Tenga en cuenta que puede generar excepciones con o sin argumentos.
Ejemplo:
raise SystemExit
sale del programa pero es posible que desee saber qué sucedió. Así que puede usar esto.
raise SystemExit("program exited")
esto imprimirá "programa salido" a stderr antes de cerrar el programa.