¿Cómo puedo generar una excepción en Python para que luego pueda ser capturada a través de un exceptbloque?

respuesta

How do I manually throw/raise an exception in 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 generar excepciones genéricas

Evita subir un genérico Exception. Para atraparlo, tendrá que atrapar todas las demás excepciones más específicas que lo subclasifican.

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 las 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: raisedeclaración

En su lugar, utilice 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') 

argsEl atributo del Exceptionobjeto accede a estos argumentos . 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, messagese agregó un atributo real a BaseExceptionfavor de alentar a los usuarios a subclasificar Exceptions y dejar de usar args, pero se retractó la introducción messagey la desaprobación original de args .

Mejores prácticas: exceptcláusula

Cuando está 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 subir. 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 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 , prefiera usar un desnudo raisepara volver a subir.

Para explicar: 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 nuevo argspara 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 al modificar los argumentos. Tenga en cuenta que esta no es una práctica recomendada y es una sintaxis no válida en Python 3 (lo que hace que mantener 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])

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

Python 3, encadenamiento de excepciones

En Python 3, puede encadenar excepciones, que preservan los rastreos:

raise RuntimeError('specific message') from error

Tenga en cuenta:

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

Métodos obsoletos:

Estos pueden ocultarse fácilmente e incluso entrar en el código de producción. Desea generar una excepción, y hacerlo 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 es válido en versiones mucho más antiguas de Python (2.4 y anteriores), es posible que todavía veas personas subiendo cadenas:

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

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

Hago 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

"I want to make an error on purpose, so that it would go into the except"

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

DON'T DO THIS. Raising a bare Exception is absolutely not the right thing to do; see Aaron Hall's excellent answer instead.

No se puede obtener mucho más pitónico que esto:

raise Exception("I know python!")

Reemplace Exceptioncon el tipo específico de excepción que desea lanzar.

Consulte los documentos de declaración de aumento para python si desea obtener más información.

En Python3 hay 4 sintaxis diferentes para rasear excepciones:

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

1. raise exception vs. 2. raise exception (args)

Si usa raise exception (args) para generar una excepción args, se imprimirá cuando imprima el objeto de excepción, como se muestra en el ejemplo a continuación.

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

raisedeclaració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 una excepción antes, raisela declaración genera una TypeErrorexcepció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. raise exception (args) from original_exception

Esta instrucción se usa 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 a continuación.

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

Producción:

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 que simplemente falla 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ó. Entonces puede usar esto.

raise SystemExit("program exited")

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

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

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

bloque es una buena manera de hacerlo. Sin embargo, aún querrá raiseexcepciones específicas para saber lo que significan.

Otra forma de lanzar excepciones es assert. Puede usar la afirmación para verificar que se cumpla una condición; de lo contrario, se generará AssertionError. Para más detalles echa 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))

Para detectar todas las excepciones, use BaseException, está en la parte superior de la jerarquía de excepciones.

#1 Atrapa la excepción

try:
    #Do something
except BaseException as error:
    print('An exception occurred: {}'.format(error))

#2 Plantea la excepción

try:
    #Do something
except BaseException as error:
    raise 'An exception occurred: {}'.format(error)

El código anterior es compatible con Python 2.7 hasta la última versión.

Referencia : https://docs.python.org/3.9/library/exceptions.html#exception-hierarchy

Deberías aprender la declaración de subida 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')

También es posible que desee generar excepciones personalizadas . Por ejemplo, si está escribiendo una biblioteca, es una muy buena práctica crear una clase de excepción base para su módulo y luego tener subexcepciones personalizadas para ser más específico.

Puedes lograrlo así:

class MyModuleBaseClass(Exception):
    pass

class MoreSpecificException(MyModuleBaseClass):
    pass


# To raise custom exceptions, you can just
# use the raise keyword
raise MoreSpecificException
raise MoreSpecificException('message')

Si no está interesado en tener una clase base personalizada, simplemente puede heredar sus clases de excepción personalizadas de una clase de excepción ordinaria como Exception, TypeError, ValueError, etc.

Si no le importa qué error generar, puede usar assertpara generar un AssertionError:

>>> assert False, "Manually raised error"
Traceback (most recent call last):
  File "<pyshell#24>", line 1, in <module>
    assert False, "Manually raised error"
AssertionError: Manually raised error
>>> 

La assertpalabra clave genera un AssertionErrorsi la condición es False, en este caso especificamos Falsedirectamente para que genere el error, pero para que tenga el texto que queremos que genere, agregamos una coma y especificamos el texto de error que queremos, en este caso Lo escribí Manually raised errory lo esta subiendo con ese texto.

si no le importa la excepción planteada, haga lo siguiente:

def crash(): return 0/0

the good old division be 0