En la introducción anterior a la sintaxis de Python, hemos encontrado los errores y excepciones dados por el intérprete, pero no los hemos explicado en detalle. Ahora estamos aprendiendo completamente Python para definir y manejar errores como los errores de sintaxis, que incluyen al menos dos errores distinguibles, que son errores y excepciones de sintaxis .
Error gramatical
Los errores de sintaxis de Python son errores que no se ajustan a la sintaxis de Python, también conocidos como errores de análisis . Este tipo de error a menudo se comete cuando Python no está familiarizado con la gramática. Por ejemplo, el siguiente ejemplo:
In [1]: if 2 == 3 print('imposible')
File "<ipython-input-1-15af39b28602>", line 1
if 2 == 3 print('imposible')
^
SyntaxError: invalid syntax
Cuando el intérprete interpreta el código anterior, encontrará que la expresión 2 == 3
seguida de dos puntos :
luego informará un error SyntaxError: invalid syntax
y mostrará la línea con el error de sintaxis y la pantalla Una "flecha" que apunta al primer error detectado en esta línea. El error es causado por el token sobre la posición indicada por la flecha (o al menos detectado aquí). El nombre del archivo y el número de línea también se imprimen para que pueda saber dónde ir cuando ingresa el archivo de script.
Los beneficios reportados por el intérprete son:
(1) Díganos qué línea de código es incorrecta;
(2) ¿Cuál es el tipo de error.
Esto es muy útil para que eliminemos los errores y corrijamos el programa.
Excepción
Si estamos familiarizados con la sintaxis, el código que escribimos es sintácticamente correcto, pero no hay garantía de que el programa no genere un error cuando se ejecute.Los errores detectados durante la ejecución se denominan excepciones , y las excepciones no llevan necesariamente a consecuencias graves, pero no las procesamos en el código, lo que puede hacer que el programa interrumpa la ejecución. Aquí hay algunas excepciones de error comunes:
In [2]: 5 / 0
----------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-2-adafc2937013> in <module>
----> 1 5 / 0
ZeroDivisionError: division by zero
In [3]: a + 3
------------------------------
NameError Traceback (most recent call last)
<ipython-input-3-d390b6b495e8> in <module>
----> 1 a + 3
NameError: name 'a' is not defined
In [4]: 10 + '1'
--------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-84c3fd9e0d8f> in <module>
----> 1 10 + '1'
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Vemos que la excepción tiene un tipo diferente, y su nombre de tipo se imprime como parte del mensaje de error. Los tipos de excepción en el ejemplo anterior son:ZeroDivisionError
, NameError
y TypeError
. Para todas las excepciones incorporadas, la cadena impresa es el nombre de la excepción incorporada. Este no es necesariamente el caso de las excepciones definidas por el usuario, pero es mejor definirlas como excepciones integradas al personalizar las excepciones. Esta es una especificación útil.El tipo de excepción estándar es un identificador incorporado, no una palabra clave reservada.
El nombre de la excepción impresa va seguido por la causa de la excepción. La primera parte del mensaje de error muestra el contexto del código cuando se produjo la excepción en forma de un seguimiento de pila. Por lo general, contiene un rastreo de pila que enumera las líneas de origen, sin embargo, no muestra las filas que se leen desde la entrada estándar.
Python tiene muchas excepciones integradas, que se heredan de BaseException
. Aquí está la relación de herencia de la excepción incorporada:
Manejo de excepciones
Dado que el programa lanzará una excepción, podemos escribir código para manejar estas excepciones. Veamos el siguiente ejemplo, que permitirá al usuario ingresar todo el tiempo hasta que la entrada sea un número entero válido. También podemos usar Control-C
para interrumpir el programa, este Control-C
causó una interrupción causará una excepción de KeyboardInterrupt.
In [6]: while 1:
...: try:
...: n = int(input('input a number:'))
...: print('You typed number:', n)
...: break
...: except ValueError:
...: print('Nooo! It is not a number, Try agin')
...:
input a number:a
Nooo! It is not a number, Try agin
input a number:b
Nooo! It is not a number, Try agin
input a number:3
You typed number: 3
Cuando ingresamos a
, no se puede convertir a un entero y se reporta una excepción de error, ValueError
. La sentencia convertida a un entero declara una excepción, y la sentencia siguiente ya no se ejecuta, sino que salta a la except
para ejecutar la sentencia dentro de ella.
try
declaración de try
funciona de la siguiente manera:
- Primero, ejecute la cláusula try , que es una declaración (una o más líneas) entre las palabras clave
try
y except
;
- Si no se produce una excepción, omita la cláusula de excepción y complete la ejecución de la cláusula de
try
;
- Si se produce una excepción al ejecutar una cláusula de prueba, se omite el resto de la cláusula. Luego, para que coincida con el tipo de excepción y la excepción después de la palabra clave de
except
, si el tipo de excepción coincide, ejecute la cláusula de excepción y luego continúe ejecutando el código detrás de la instrucción try.
- Si la excepción que ocurre no coincide con la excepción después de la excepción, pásela a la declaración de prueba externa. Si no se encuentra ningún código de procesamiento, es una
未处理异常
y la ejecución se detendrá con un mensaje de error.
Una declaración de try
puede tener varias cláusulas de excepción, de modo que diferentes manipuladores manejan diferentes excepciones. Cada vez que se encuentra una excepción, a lo sumo se ejecuta una cláusula de excepción, es decir, el controlador solo procesa la excepción correspondiente y no controla las excepciones de otros controladores en la misma declaración de intento. Sin embargo, una cláusula de excepción puede incluir varias excepciones en una tupla, por ejemplo:
try:
...
except (RuntimeError, TypeError, NameError):
pass
Las excepciones se heredan de BaseException
. Si la clase en la cláusula de excepción es la misma clase que la excepción que ocurrió, o la clase base de la excepción (la clase principal), la excepción es compatible con la clase en la cláusula de excepción. Sin embargo, lo contrario no es cierto. Veamos el código a continuación, que imprimirá B, C, D a la vez.
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B")
Si invierto la cláusula de excepción y coloco la excepción B en la primera, ¿adivina qué se imprimirá? La respuesta es que imprimirá B, B, B. Es decir, la primera cláusula de excepción coincidente se activa porque B es el padre de C y D.
La última cláusula de excepción puede omitir el nombre de la excepción para usarla como comodín para que coincida con todas las excepciones. ¡Debe usarse con cuidado porque es fácil cubrir errores de programación reales! Pero se puede usar para imprimir un mensaje de error y luego volver a lanzar la excepción (también permite que la persona que llama maneje la excepción):
import sys
try:
f = open('zzz.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert string to integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise
La declaración de prueba tiene una cláusula else opcional que debe colocarse después de todas las cláusulas excepto cuando está en uso. Es útil para el código que debe ejecutarse cuando la cláusula try no genera una excepción. Por ejemplo:
try:
f = open('zzz.txt', 'r')
except OSError:
print('cannot open', 'zzz.txt')
else:
print('zzz.txt', 'has', len(f.readlines()), 'lines')
f.close()
La ventaja de utilizar la cláusula else
es que evita la captura accidental de excepciones generadas por la cláusula else. Es decir, en el programa solo queremos detectar la excepción generada por open
, no el error causado por f.readlines()
.
Una excepción puede tener un valor asociado cuando se lanza, llamado parámetro de excepción. La existencia y el tipo del parámetro dependen del tipo de excepción.
La cláusula de excepción puede especificar una variable después del nombre de la excepción. Esta variable es una instancia de la excepción y sus argumentos se almacenan en instance.args
. Para mayor comodidad, la instancia de excepción define __str__()
, por lo que puede imprimir los parámetros directamente sin hacer referencia a .args
. También puede crear una excepción antes de lanzarla y agregarle propiedades según sea necesario. :
In [7]: try:
...: raise Exception('learn', 'Python')
...: except Exception as e:
...: print(type(e))
...: print(e.args)
...: print(e)
...: a, b = e.args
...: print('a =', a)
...: print('b =', b)
...:
<class 'Exception'>
('learn', 'Python')
('learn', 'Python')
a = learn
b = Python
El controlador de excepciones puede manejar no solo las excepciones encontradas en la cláusula try, sino también las excepciones internas de las funciones llamadas en la cláusula try, por ejemplo:
In [8]: def func():
...: return 10/0
...:
In [9]: try:
...: func()
...: except ZeroDivisionError as err:
...: print('run-time error:', err)
...:
run-time error: division by zero
留言
張貼留言