Maison >développement back-end >Tutoriel Python >Introduction à deux types d'erreurs en Python
Nous n'avons pas beaucoup parlé des messages d'erreur jusqu'à présent, mais ils ont été utilisés dans quelques exemples. Python a au moins deux types d'erreurs : Erreur de syntaxe et Exception
Les erreurs de syntaxe, également appelées erreurs d'analyse, sont Python Une plainte courante chez les débutants.
>>> while True print('Hello world') File "<stdin>", line 1while True print('Hello world') ^SyntaxError: invalid syntax
L'analyseur Python imprime à plusieurs reprises la ligne d'erreur et affiche une petite flèche pointant vers la position dans la ligne d'erreur où l'erreur a été détectée pour la première fois. L'erreur est provoquée par l'instruction avant la flèche (du moins c'est ce qui est détecté) : Dans l'exemple ci-dessus, l'erreur est détectée dans la fonction print()
car les deux points :
avant sont manquants. Le nom du fichier et le numéro de ligne sont également imprimés, ce qui facilite la localisation des problèmes lorsque le programme provient d'un script.
Même si l'instruction ou l'expression est grammaticalement correcte, des erreurs peuvent survenir lors de l'exécution. Les problèmes détectés lors de l'exécution sont appelés Exceptions Les exceptions ne sont pas des erreurs absolument fatales : nous présenterons ensuite comment gérer les exceptions en Python. Cependant, la plupart des exceptions ne seront pas gérées par le programme et finiront par devenir des messages d'erreur, comme indiqué ci-dessous :
>>> 10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in <module>ZeroDivisionError: division by zero>>> 4 + spam*3Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'spam' is not defined>>> '2' + 2Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: Can't convert 'int' object to str implicitly
La dernière ligne du message d'erreur indique ce qui s'est passé. Il existe différents types d'exceptions, et les types sont également imprimés dans le cadre du message d'erreur : les types dans l'exemple ci-dessus sont l'exception de division par zéro ZeroDivisionError
, l'exception de nom NameError
et l'exception de type TypeError
. La chaîne imprimée comme type d'exception est le nom de l'exception intégrée. Cela est vrai pour toutes les exceptions intégrées, et bien que cette convention soit utile, toutes les exceptions définies par l'utilisateur n'y adhéreront pas. Les noms d'exceptions standard sont des identifiants intégrés (et non des mots réservés).
Les lignes restantes affichent des informations détaillées basées sur le type d'exception et la raison pour laquelle l'exception s'est produite.
La partie précédente du message d'erreur affiche les informations contextuelles de l'exception sous forme de traceback de pile. Normalement, les lignes de code source sont répertoriées dans le traçage de la pile. Cependant, lorsque le programme lit à partir de l'entrée standard, les lignes ne sont pas affichées.
Les exceptions intégrées répertorient toutes les exceptions intégrées et leur signification.
Les programmes Python permettent la gestion des exceptions spécifiées. Le programme suivant nécessite que l'utilisateur boucle l'entrée jusqu'à ce que l'entrée soit un entier valide, mais le programme peut également être interrompu (en utilisant Control-C
ou d'autres moyens pris en charge par le système d'exploitation) ; . L'ordre d'exécution des instructions
while True:try: x = int(input("Please enter a number: "))breakexcept ValueError:print("Oops! That was no valid number. Try again...")
try
est :
Tout d'abord, exécutez les instructions entre try
et except
clause try
Si aucune exception ne se produit, ignorez la clause except et l'instruction try
est exécutée
Si une exception se produit lors de l'exécution de la clause try, les instructions restantes de la clause sont ignorées. Ensuite, si le type d'exception émis peut correspondre à l'exception après le mot-clé except
, alors la clause except est exécutée, puis l'instruction après l'instruction try
continue d'être exécutée.
Si une exception se produit mais qu'il n'y a pas d'exception correspondante après except, alors l'exception est levée vers l'instruction try
externe si l'exception ne peut pas être gérée, l'exception devient Exception non gérée , provoquant la fin du programme et l'impression d'un message comme dans l'exemple ci-dessus.
peut avoir plusieurs clauses except pour spécifier des méthodes de gestion pour différentes exceptions. Au plus une clause except sera exécutée. Le gestionnaire ne gérera que les exceptions qui se produisent dans la clause try correspondante, pas les exceptions qui se produisent dans d'autres gestionnaires dans la même instruction try
. Une clause except peut lister plusieurs exceptions à l'aide d'un tuple entre parenthèses, comme ceci : try
... except (RuntimeError, TypeError, NameError): ... pass
Une classe dans la clause peut correspondre aux types dont la classe enfants ou à son propre type d'exception (mais pas l'inverse, les sous-classes de la clause except ne correspondront pas aux exceptions de la classe parent). Par exemple, le code suivant affichera B, C, D dans l'ordre : except
class B(Exception):passclass C(B):passclass D(C):passfor cls in [B, C, D]:try:raise cls()except D:print("D")except C:print("C")except B:print("B")
en premier), alors B sera imprimé, B, B - La correspondance de la première clause except est déclenchée. except B
import systry: 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
... L'instruction try
a un clause else except
, cette clause ne peut apparaître qu'après toutes les clauses sauf les clauses. Si une section de code doit être exécutée alors que la clause try ne lève pas d'exception, il est utile d'utiliser la clause else (Annotation : La clause sera ignorée par ). Par exemple : else
return, break, continue
使用 else
子句比在 try
子句中附加代码要好,因为这样可以避免 try
... except
意外的捕获的本不属于它们保护的那些代码抛出的异常。
异常发生时,可以携带与之关联的值,也称作异常参数。异常参数是否可以存在以及其类型取决于异常类型。
except子句可以在异常名字后指定变量。该变量绑定到异常实例,异常参数存储在instance.args
属性中。方便起见,异常实例定义了__str__()
以便异常参数可以直接打印,而不是使用.args
引用。也可以首先实例化异常,并在抛出它之前加入任何想要的参数:
>>> try: ... raise Exception('spam', 'eggs') ... except Exception as inst: ... print(type(inst)) # the exception instance... print(inst.args) # arguments stored in .args... print(inst) # __str__ allows args to be printed directly,... # but may be overridden in exception subclasses... x, y = inst.args # unpack args... print('x =', x) ... print('y =', y) ...<class 'Exception'>('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs
对于未处理异常来说,如果它有参数,那么参数将在错误信息的后面部分(详细信息部分)打印。
异常处理程序不仅仅会处理即时发生在try子句中的异常,还会处理try子句中直接或者间接调用的函数中发生的异常。例如:
>>> def this_fails(): ... x = 1/0...>>> try: ... this_fails() ... except ZeroDivisionError as err: ... print('Handling run-time error:', err) ... Handling run-time error: division by zero
raise语句允许程序员强制发生异常。例如:
>>> raise NameError('HiThere') Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: HiThere
raise
的唯一参数指定要抛出的异常。参数必须是异常实例或者异常类(继承自Exception类的子类)。如果参数是异常类型,会隐式使用无参方式调用异常的构造器初始化一个异常实例:
raise ValueError # shorthand for 'raise ValueError()'
如果需要捕获异常但是不处理,一种更简单形式的raise
语句允许重新抛出这个异常:
>>> try: ... raise NameError('HiThere') ... except NameError: ... print('An exception flew by!') ... raise... An exception flew by!Traceback (most recent call last): File "<stdin>", line 2, in <module>NameError: HiThere
程序中可以通过创建新异常类的方式提出自己的异常(参见Classes
获取Python类的更多信息)。异常必须直接或者间接继承自Exception
类。
自定义异常类拥有其他类的功能,但通常需要保持其简洁性,只提供几个供异常处理程序提取错误信息的属性。需要创建一个抛出若干不同错误的模块时,比较好的实践是,为定义在这个模块中的异常创建父类,由子类创建对应不同错误的具体异常:
class Error(Exception):"""Base class for exceptions in this module."""passclass 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 = expressionself.message = messageclass 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 = previousself.next = nextself.message = message
与标准异常类类似,大多数异常的名字都以"Error"结尾。
许多标准模块都定义了自己的异常,这些异常对应模块中定义的函数中可能发生的错误。更多信息参考Classes。
try
语句有可选的在任何情况下都会执行的子句,可用于定义清理动作。例如:
>>> try: ... raise KeyboardInterrupt... finally: ... print('Goodbye, world!') ... Goodbye, world!KeyboardInterruptTraceback (most recent call last): File "<stdin>", line 2, in <module>
无论是否有异常发生,finally子句在离开try
语句之前总是会执行。当try
子句中有异常发生并且没有被except
子句处理(或者异常发生在except
子句或else
子句),finally
子句执行之后,这些异常会重新抛出。当try
语句的其他子句通过break, continue
或者return
语句离开时,finally
子句也会执行。以下是较为复杂的示例:
>>> def divide(x, y): ... 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.0executing 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 <module> File "<stdin>", line 3, in divideTypeError: unsupported operand type(s) for /: 'str' and 'str'
正如所见的那样,finally
子句在任何情况下都会执行。两个字符串相除产生的TypeError
异常没有被except
子句处理,因此在finally
子句执行完毕之后被重新抛出。
在实践应用中,finally
子句用来释放外部资源(比如文件和网络连接),不论资源的使用是否成功。
一些对象定义了标准的清理动作,当不再需要这些对象时,会执行清理动作,而不论使用对象的操作是否成功。以下示例读取文件并打印内容到显示器:
for line in open("myfile.txt"):print(line, end="")
这段代码的问题是:当代码执行完毕后,文件会保留打开状态一段不确定的时间。这在简单的脚本中不是什么大问题,但是在大型的应用程序中会出问题。with
语句使得像文件一样的对象可以被立即准确回收。
with open("myfile.txt") as f:for line in f:print(line, end="")
语句执行后,即使在执行代码时遇到问题,文件f总是会被关闭。像文件一样提供预定义清理动作的对象会在其说明文档中指示这点。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!