Generar (lanzar) manualmente una excepción en Python

¿Cómo puedo generar una excepción en Python para que luego pueda detectarse a través de un except ¿bloquear?

preguntado el 12 de enero de 10 a las 18:01

8 Respuestas

¿Cómo lanzo / levanto manualmente una excepción en Python?

Utilice el constructor de excepciones más específico que se ajuste semánticamente a su problema.

Sea específico en su mensaje, por ejemplo:

raise ValueError('A very specific bad thing happened.')

No plantee excepciones genéricas

Evite levantar un genérico Exception. Para detectarlo, tendrá que detectar todas las demás excepciones más específicas que lo subclasifiquen.

Problema 1: Ocultar 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 se atrapa

Y capturas más específicas no detectará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

Mejores prácticas: raise ambiental

En su lugar, use el constructor de excepciones más específico que se ajuste semánticamente a su problema.

raise ValueError('A very specific bad thing happened')

que también permite pasar un número arbitrario de argumentos al constructor:

raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz') 

Estos argumentos son accedidos por el args Atributo en el Exception objeto. 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, un message el atributo fue agregado a BaseException a favor de alentar a los usuarios a subclasificar Excepciones y dejar de usar args, pero la introducción de message y la desaprobación original de argumentos se ha retirado.

Mejores prácticas: except cláusula

Cuando esté dentro de una cláusula except, es posible que desee, por ejemplo, registrar que ocurrió un tipo específico de error y luego volver a generar. La mejor manera de hacer esto mientras se conserva el seguimiento de la pila es usar una declaración de aumento simple. 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 la 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 un desnudo raise 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 un nuevo args por ejemplo:

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 esto es no es una buena práctica y es sintaxis inválida en Python 3 (lo que hace que mantener la compatibilidad sea mucho más difícil de evitar).

>>> 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>

In 3 Python:

raise error.with_traceback(sys.exc_info()[2])

Nuevamente: evite manipular los rastreos manualmente. Es menos eficiente y más propenso a errores. Y si estás usando subprocesos y sys.exc_info incluso puede obtener un rastreo incorrecto (especialmente si está utilizando el manejo de excepciones para el flujo de control, lo que personalmente tendería a evitar).

Python 3, encadenamiento de excepciones

En Python 3, puede encadenar Excepciones, que conservan los rastreos:

raise RuntimeError('specific message') from error

Se consciente:

  • este permitir cambiar el tipo de error planteado, y
  • esto es no compatible con Python 2.

Métodos obsoletos:

Estos se pueden ocultar fácilmente e incluso ingresar al código de producción. Desea generar una excepción y, al hacerlo, se generará una excepción, ¡pero no el previsto!

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 subiendo las cuerdas:

raise 'message' # really really wrong. don't do this.

En todas las versiones modernas, esto realmente generará un TypeError, porque no estás levantando un BaseException tipo. 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

Genero Excepciones para advertir a los consumidores de mi API si la están usando incorrectamente:

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)))

Cree sus propios tipos de error cuando sea apropiado

"Quiero cometer un error a propósito, para que entre en el excepto"

Puede crear sus propios tipos de error, si desea indicar que algo específico está mal en su aplicación, simplemente subclase el 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.')

Respondido 15 Feb 21, 08:02

try: raise ValueError ('error') excepto ValueError como e: print ('detectaremos la excepción: Exception', str (e)) #es la mejor solución - sharath bj

@SharathBJ estás levantando un ValueError y reportarlo como el tipo, Exceptiony eso es una pérdida innecesaria de precisión. repr(e) al menos informará el tipo por usted. - Aaron Hall ♦

¿Dónde está la documentación oficial que muestra que puede pasar un mensaje al presentar una excepción? ex: raise TypeError("my message") - grapas gabriel

@GabrielStaples aquí están los documentos sobre argumentos de instanciación: docs.python.org/3/library/exceptions.html#BaseException.args - Aaron Hall ♦

@AaronHall, ah, ya veo. No me di cuenta del tipo de excepción, como TypeError, fue una llamada a un constructor de clases! Tiene sentido ahora. Por lo tanto, el mensaje es un argumento de constructor común para clases de tipo de error. - grapas gabriel

NO HAGAS ESTO. Levantando un desnudo Exception es absolutamente no lo correcto a hacer; ver La excelente respuesta de Aaron Hall preferiblemente.

No puedo ser mucho más pitónico que esto:

raise Exception("I know python!")

Ver los documentos de declaración de aumento para Python si desea más información.

contestado el 23 de mayo de 17 a las 11:05

¡No por favor! Esto elimina la posibilidad de ser específico acerca de lo que atrapa. Es TOTALMENTE la forma incorrecta de hacerlo. Eche un vistazo a la excelente respuesta de Aaron Hall en lugar de esta. En momentos como este, me gustaría poder dar más de un voto negativo por respuesta. - Dawud ibn Karim

@PeterR Es igualmente terrible que tenga tan pocos votos negativos. Para CUALQUIERA que lea esta respuesta, ¡NO HAGA ESTO NUNCA! La respuesta correcta es la de Aaron Hall. - Dawud ibn Karim

Creo que debería haber una explicación más detallada de por qué esto está mal o es tan malo. - Charlie Parker

@CharlieParker Lo hay. Es la primera parte de La respuesta de Aaron Hall. - dinei

¿Por qué no se puede marcar esta respuesta para su eliminación? ¡Ya tiene 93 votos negativos! - códigoforester

En Python3 hay 4 sintaxis diferentes para las excepciones rasantes:

1. raise exception 
2. raise exception (args) 
3. raise
4. raise exception (args) from original_exception

1. generar excepción frente a 2. generar excepción (argumentos)

Si utiliza raise exception (args) para plantear una excepción, entonces el args se imprimirá cuando imprima el objeto de excepción, como se muestra en el ejemplo siguiente.

  #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.aumentar

raise declaración sin ningún argumento vuelve a generar la última excepción. Esto es útil si necesita realizar algunas acciones después de detectar la excepción y luego desea volver a generarla. Pero si no hubo excepción antes, raise declaración eleva TypeError Excepción.

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 una excepción (argumentos) de original_exception

Esta declaración se utiliza para crear un encadenamiento de excepciones en el que una excepción que se genera en respuesta a otra excepción puede contener los detalles de la excepción original, como se muestra en el ejemplo siguiente.

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

Respondido el 04 de diciembre de 19 a las 08:12

Tenga en cuenta que PEP8 prefiere exception(args) encima exception (args) - ojo brillante

También hay raise exception(args) from None decir que la excepción actualmente activa fue manejada y ya no es de interés. De lo contrario, si genera una excepción dentro de un except bloque y no se maneja, los rastreos para ambas excepciones se mostrarán separados por el mensaje "Durante el manejo de la excepción anterior, se produjo otra excepción" - cg909

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 detectar, sino simplemente fallar rápidamente para permitirle depurar desde allí si alguna vez sucede, la más lógica parece ser AssertionError:

if 0 < distance <= RADIUS:
    #Do something.
elif RADIUS < distance:
    #Do something.
else:
    raise AssertionError("Unexpected value of 'distance'!", distance)

contestado el 19 de mayo de 15 a las 05:05

Este es un mejor caso para ValueError que AssertionError porque no hay ningún problema con una afirmación (porque aquí no se hace ninguna), el problema está en un valor. Si realmente quieres un AssertionError en este caso, escribe assert distance > 0, 'Distance must be positive'. Pero no debe verificar los errores de esa manera porque las afirmaciones se pueden desactivar (python -O). - Alquimista de dos bits

@ Two-BitAlchemist Buen punto. La idea se perdió en la simplificación cuando escribí el ejemplo simple anterior. En muchos casos similares, es una condición que no está asociada con un valor en particular. Más bien, el significado es "el flujo de control nunca debería llegar aquí". - Evgeni Serguéiev

Las afirmaciones de @ Two-BitAlchemist se pueden desactivar, sí, pero ¿no debería usarlas para verificar errores en absoluto? - Evgeni Serguéiev

Bueno, eso depende. No permitiría que ese sea mi único error al verificar un programa que tengo la intención de distribuir. Por otro lado, podría hacer un programa solo para mis compañeros de trabajo y decirles que lo usan bajo su propio riesgo si lo ejecutan con -O. - Alquimista de dos bits

@ Two-BitAlchemist Para mí, el papel de las afirmaciones no es la verificación de errores per se (que es para lo que están las pruebas), sino que establecen vallas dentro del código que ciertos errores no pueden atravesar. Por lo tanto, es más fácil rastrear y aislar los errores, que inevitablemente ocurrirán. Estos son solo buenos hábitos que requieren poco esfuerzo, mientras que las pruebas requieren mucho esfuerzo y mucho tiempo. - Evgeni Serguéiev

Primero lea 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ó, por lo que puede usar esto.

raise SystemExit("program exited")

esto imprimirá "programa salido" a stderr antes de cerrar el programa.

Respondido el 02 de diciembre de 17 a las 12:12

¿No es esto contra el paradigma OOP? Supongo que el primer caso arroja la referencia de clase y el segundo una instancia de SystemSalir. No lo haria raise SystemExit() ser la mejor opcion? ¿Por qué funciona el primero? - quemado

Otra forma de lanzar excepciones es assert. Puede usar la aserción para verificar que se está cumpliendo una condición; de lo contrario, se generará AssertionError. Para más detalles eche un vistazo aquí.

def avg(marks):
    assert len(marks) != 0,"List is empty."
    return sum(marks)/len(marks)

mark2 = [55,88,78,90,79]
print("Average of mark2:",avg(mark2))

mark1 = []
print("Average of mark1:",avg(mark1))

Respondido 27 Feb 19, 09:02

no es infalible ya que las afirmaciones en CPython se ignoran cuando el intérprete recibe la señal de optimizaciones (-O); si realmente desea controlar el flujo del programa "oye, esta condición no debería suceder, pero terminará anormalmente si es cierto", manualmente raise AssertionError() - vaquero

Solo para tener en cuenta: hay ocasiones en las que DEBE manejar excepciones genéricas. Si está procesando un montón de archivos y registrando sus errores, es posible que desee detectar cualquier error que se produzca en un archivo, registrarlo y continuar procesando el resto de los archivos. En ese caso, un

try:
    foo() 
except Exception as e:
    print(str(e)) # Print out handled error

bloquear es una buena forma de hacerlo. Todavía querrás raise excepciones específicas para que sepa lo que significan.

Respondido 04 Jul 20, 18:07

Deberías aprender la declaración de aumento de Python para eso. Debe mantenerse dentro del bloque try. Ejemplo -

try:
    raise TypeError            #remove TypeError by any other error if you want
except TypeError:
    print('TypeError raised')

respondido 31 mar '20, 09:03

¿Puede dar una razón de por qué su ejemplo es bueno? He leído todas las respuestas a esta y tengo mucha curiosidad. - Brian

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.