Errores y excepciones de Python3
Como principiante en Python, al comenzar a aprender programación en Python, a menudo verás mensajes de error. No los hemos mencionado anteriormente; en este capítulo los presentaremos específicamente.
Python tiene dos tipos de errores fáciles de reconocer: errores de sintaxis y excepciones.
Python assert (aserción) se utiliza para evaluar una expresión; cuando la condición de la expresión es false, se desencadena una excepción.

Errores de sintaxis
Los errores de sintaxis de Python, también llamados errores de análisis, son comunes entre los principiantes, como en el siguiente ejemplo:
File "<stdin>", line 1, in ?
while True print('Hello world')
^
SyntaxError: invalid syntax
En este ejemplo, se detectó un error en la función print(): le faltan dos puntos (:) delante.: 。
El analizador sintáctico señala la línea donde ocurrió el error y marca una pequeña flecha en la posición del primer error encontrado.
Excepciones
Incluso si la sintaxis de un programa Python es correcta, pueden ocurrir errores al ejecutarlo. Los errores detectados en tiempo de ejecución se denominan excepciones.
La mayoría de las excepciones no son manejadas por el programa y se muestran aquí en forma de mensajes de error:
Ejemplos
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ZeroDivisionError: division by zero
>>> 4 + spam*3 # spam no está definido, se desencadena una excepción
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2 # int no se puede sumar con str, se desencadena una excepción
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
Las excepciones aparecen en diferentes tipos, y estos tipos se imprimen como parte de la información: en los ejemplos, los tipos son ZeroDivisionError, NameError y TypeError.
La parte inicial del mensaje de error muestra el contexto donde ocurrió la excepción y presenta la información detallada en forma de pila de llamadas.
Manejo de excepciones
try/except
La captura de excepciones se puede realizar con latry/exceptsentencia.

En el siguiente ejemplo, se pide al usuario que introduzca un entero válido, pero se le permite interrumpir el programa (usando Control-C o el método proporcionado por el sistema operativo). La interrupción del usuario provocará una excepción KeyboardInterrupt.
try:
x = int(input("Por favor, ingresa un número: "))
break
except ValueError:
print("Lo que ingresaste no es un número, ¡vuelve a intentarlo!")
La sentencia try funciona de la siguiente manera:
Primero, se ejecuta la cláusula try (las sentencias entre la palabra clave try y la palabra clave except).
Si no ocurre ninguna excepción, se ignora la cláusula except, y la cláusula try termina después de ejecutarse.
Si ocurre una excepción durante la ejecución de la cláusula try, se ignora el resto de la cláusula try. Si el tipo de la excepción coincide con el nombre después de except, se ejecutará la cláusula except correspondiente.
Si una excepción no coincide con ningún except, la excepción se transmitirá al try de nivel superior.
Una sentencia try puede contener varias cláusulas except para manejar diferentes excepciones específicas. Como máximo solo se ejecutará una rama.
Los manejadores solo manejarán las excepciones de la cláusula try correspondiente, no las excepciones de otros manejadores try.
Una cláusula except puede manejar varias excepciones a la vez; estas excepciones se colocan entre paréntesis formando una tupla, por ejemplo:
pass
La última cláusula except puede omitir el nombre de la excepción, y se usará como comodín. Puedes usar este método para imprimir un mensaje de error y luego volver a lanzar la excepción.
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise
try/except...else
try/exceptLa sentencia también tiene unaelsecláusula opcional; si se usa esta cláusula, debe colocarse después de todas las cláusulas except.
La cláusula else se ejecutará cuando no haya ocurrido ninguna excepción en la cláusula try.

El siguiente ejemplo determina si un archivo se puede abrir en la sentencia try. Si al abrir el archivo todo es normal y no ocurre ninguna excepción, se ejecuta la parte de else y se lee el contenido del archivo:
try:
f = open(arg, 'r')
except IOError:
print('cannot open', arg)
else:
print(arg, 'has', len(f.readlines()), 'lines')
f.close()
Usar la cláusula else es mejor que poner todas las sentencias dentro de la cláusula try, porque así se evitan algunas excepciones inesperadas que except no puede capturar.
El manejo de excepciones no solo maneja las excepciones que ocurren directamente en la cláusula try, sino también las excepciones lanzadas en las funciones llamadas desde la cláusula (incluso en funciones llamadas indirectamente). Por ejemplo:
x = 1/0
>>> try:
this_fails()
except ZeroDivisionError as err:
print('Handling run-time error:', err)
Handling run-time error: int division or modulo by zero
Sentencia try-finally
La sentencia try-finally ejecutará el código final sin importar si ocurre o no una excepción.

En el siguiente ejemplo, la sentencia finally se ejecutará tanto si ocurre una excepción como si no:
Ejemplos
ejemplo()
except AssertionError as error:
print(error)
else:
try:
with open('file.log') as file:
read_data = file.read()
except FileNotFoundError as fnf_error:
print(fnf_error)
finally:
print('Esta frase se ejecutará sin importar si ocurre una excepción o no.')
Lanzar excepciones
Python utiliza la sentencia raise para lanzar una excepción específica.
La sintaxis de raise es la siguiente:
raise [Exception [, args [, traceback]]]

El siguiente ejemplo desencadena una excepción si x es mayor que 5:
if x > 5:
raise Exception('x no puede ser mayor que 5. El valor de x es: {}'.format(x))
Ejecutar el código anterior desencadenará una excepción:
Traceback (most recent call last):
File "test.py", line 3, in <module>
raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
Exception: x 不能大于 5。x 的值为: 10
El único parámetro de raise especifica la excepción que se va a lanzar. Debe ser una instancia de excepción o una clase de excepción (es decir, una subclase de Exception).
Si solo quieres saber si se ha lanzado una excepción y no deseas manejarla, una simple sentencia raise puede volver a lanzarla.
raise NameError('HiThere') # Simula una excepción.
except NameError:
print('An exception flew by!')
raise
An exception flew by!
Traceback (most recent call last):
File "<stdin>", line 2, in ?
NameError: HiThere
Excepciones definidas por el usuario
Puedes tener tus propias excepciones creando una nueva clase de excepción. La clase de excepción hereda de la clase Exception, ya sea directa o indirectamente, por ejemplo:
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
>>> try:
raise MyError(2*2)
except MyError as e:
print('My exception occurred, value:', e.value)
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
__main__.MyError: 'oops!'
En este ejemplo, el __init__() predeterminado de la clase Exception se sobrescribe.
Cuando se crea un módulo que puede lanzar varios tipos diferentes de excepciones, una práctica habitual es establecer una clase de excepción base para el paquete y, basándose en esta clase base, crear diferentes subclases para distintas situaciones de error:
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
class TransitionError(Error):
"""Raised when an operation attempts a state transition that's not
allowed.
Attributes:
previous -- state at beginning of transition
next -- attempted new state
message -- explanation of why the specific transition is not allowed
"""
def __init__(self, previous, next, message):
self.previous = previous
self.next = next
self.message = message
La mayoría de los nombres de las excepciones terminan en 'Error', igual que la nomenclatura estándar de excepciones.
Definir acciones de limpieza
La sentencia try tiene otra cláusula opcional que define una acción de limpieza que se ejecutará en cualquier caso. Por ejemplo:
... raise KeyboardInterrupt
... finally:
... print('Goodbye, world!')
...
Goodbye, world!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyboardInterrupt
En el ejemplo anterior, la cláusula finally se ejecutará sin importar si ocurrió una excepción en la cláusula try.
Si se lanza una excepción en la cláusula try (o en las cláusulas except y else) y ningún except la captura, dicha excepción se lanzará después de ejecutarse la cláusula finally.
A continuación se muestra un ejemplo más complejo (que incluye cláusulas except y finally en la misma sentencia try):
try:
result = x / y
except ZeroDivisionError:
print("division by zero!")
else:
print("result is", result)
finally:
print("executing finally clause")
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
Acciones de limpieza predefinidas
Algunos objetos definen acciones de limpieza estándar. Una vez que el objeto ya no es necesario, se ejecuta esta acción de limpieza estándar, sin importar si el sistema lo utilizó con éxito o no.
El siguiente ejemplo muestra cómo intentar abrir un archivo y luego imprimir su contenido en pantalla:
print(line, end="")
El problema del código anterior es que, después de ejecutarse, el archivo permanece abierto y no se cierra.
La sentencia con la palabra clave with garantiza que objetos como los archivos ejecutarán correctamente su método de limpieza después de su uso:
for line in f:
print(line, end="")
Después de ejecutar el código anterior, incluso si surge un problema durante el proceso, el archivo f siempre se cerrará.
Para más contenido sobre la palabra clave with, consulta:La palabra clave with en Python