Maison  >  Article  >  développement back-end  >  Comprendre le mécanisme d'exception de Python

Comprendre le mécanisme d'exception de Python

coldplay.xixi
coldplay.xixiavant
2021-03-10 10:00:332920parcourir

Préface : Lorsque je travaillais auparavant, j'utilisais Python pour compléter une fenêtre de ligne de commande qui utilisait le port série pour envoyer SCPI et interagir avec le microcontrôleur. en implémentant la fonction, j'ai découvert que python était utilisé pour traiter les données. Le résultat, qu'il s'agisse du retour de la valeur finale correcte ou du retour d'une valeur d'erreur, peut être directement renvoyé à l'interface principale. Évidemment, il n'est pas possible de renvoyer directement des données ayant des significations différentes, c'est pourquoi un mécanisme d'exception est utilisé pour gérer les données ayant des valeurs erronées. Comme je ne connaissais pas grand-chose aux anomalies auparavant, j'ai vérifié certaines informations ici et compilé quelques notes.

Comprendre le mécanisme d'exception de Python

Table des matières de l'article

  • Compréhension des exceptions
    • 1. Qu'est-ce qu'une exception
    • 2. La différence entre les erreurs et les exceptions
    • 3. Types courants d'exceptions Python
  • 2. Les cinq principaux mécanismes de gestion des exceptions de Python
    • 1. Mécanisme de gestion des exceptions par défaut
    • 2. mécanisme
    • 3. essayez...sauf...enfin.... mécanisme de traitement
    • 4. mécanisme de traitement des assertions
    • 5. mécanisme
  • 3. Personnalisation des exceptions Python
    • 1. Personnalisation des exceptions
    • 2. > 3. Détection des exceptions
    4. Précautions d'utilisation des exceptions
  • 1. Ne vous fiez pas trop au mécanisme d'exception
    • 2. N'introduisez pas trop de code dans le bloc try
    • 3 N'ignorez pas les exceptions interceptées
  • Résumé
  • <.>

  • (Recommandation d'apprentissage gratuite :

Tutoriel vidéo Python) 1. Compréhension des exceptions


1. Qu'est-ce qu'une anomalie

  L'anomalie signifie « différent des conditions normales », qu'est-ce qui est normal ? Normal signifie que lorsque l'interprète interprète le code, le code que nous écrivons est conforme aux règles définies par l'interprète, ce qui est normal lorsque l'interprète constate que un certain morceau de code est conforme à la grammaire mais peut être anormal , l'interprète émettra un événement pour interrompre l'exécution normale du programme. Ce signal d'interruption est un

signal d'exception

. Par conséquent, l'explication générale est que lorsque l'interpréteur détecte une erreur dans le programme, une exception sera générée si le programme ne la gère pas, l'exception sera levée et le programme se terminera . Nous pouvons écrire un int ("m") dans un fichier .py vierge, et le résultat après exécution est le suivant.   Cette chaîne de polices est une série de messages d'erreur renvoyés par l'interpréteur, car les paramètres passés dans int() ne prennent en charge que les chaînes numériques et les nombres, évidemment 'm' n'appartient pas à un nombre Le paramètre de chaîne d'entrée est erroné, donc l'interpréteur signale une erreur "valueError".
Comprendre le mécanisme dexception de Python

2. La différence entre les erreurs et les exceptions

Aperçu des erreurs python : Il fait référence à des erreurs de syntaxe ou de logique avant l'exécution du code . Prenons l'exemple des erreurs de syntaxe régulières. Lorsque le code que nous écrivons ne réussit pas le test de syntaxe, une erreur de syntaxe apparaîtra directement avant l'exécution du programme. Sinon, le code écrit n'aura aucun sens. et ne peut pas être exécuté. Par exemple, si a = 1 print("hello") est entré dans le fichier .py, le résultat de sortie est le suivant :

  Traceback (most recent call last):
  	File "E:/Test_code/test.py",line 1
    	if a = 1 print("hello")
                ^SyntaxError: invalid syntax

  La fonction print() s'est avérée avoir une erreur, c'est-à-dire qu'il y a il manque deux points devant : , L'analyseur va donc reproduire la ligne de code avec l'erreur de syntaxe et utiliser une petite "flèche" pour pointer sur la première erreur détectée dans la ligne, afin que l'on puisse trouver directement la position correspondante et modifier sa syntaxe. Bien entendu, en plus des erreurs grammaticales, il existe également de nombreuses erreurs de plantage du programme, telles qu'un débordement de mémoire, etc. Ces erreurs sont souvent relativement cachées.  Par rapport aux erreurs, Les exceptions Python se produisent principalement lorsque le programme rencontre des problèmes logiques ou algorithmiques

lors de l'exécution du programme. Si l'interpréteur peut le gérer, alors il n'y a pas de problème. S'il ne peut pas le gérer, le programme. sera terminé directement, une exception sera levée, comme l'exemple int('m') au premier point, où l'erreur de programme se produit parce que le paramètre est passé de manière incorrecte. Il existe toutes sortes d'exceptions causées par la logique. Heureusement, notre interprète a intégré différents types d'exceptions, nous permettant de savoir quels types d'exceptions se produisent, afin que nous puissions « prescrire le bon médicament ».

Notez ici que les erreurs de syntaxe ci-dessus sont des erreurs reconnues, donc l'interpréteur lancera également un message d'exception SyntaxError par défaut pour renvoyer au programmeur. Donc, en substance, la plupart des erreurs peuvent être générées et imprimées, mais comme le code d'erreur ne s'exécute pas, il ne peut pas être géré, donc la capture des informations sur les exceptions d'erreur n'a plus de sens.
3. Types d'exceptions Python courants

 Voici les types d'exceptions les plus courants lorsque nous écrivons du code. Si vous rencontrez d'autres types d'exceptions, bien sûr, choisissez le blanc. Enregistrer~

异常名称 名称解析
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeropisionError 除(或取模)零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告

二、python五大异常处理机制

  我们明白了什么是异常后,那么发现异常后怎么处理,便是我们接下来要解决的问题。这里将处理异常的方式总结为五种。

1、默认异常处理机制

  “默认”则说明是解释器默认做出的行为,如果解释器发现异常,并且我们没有对异常进行任何预防,那么程序在执行过程中就会中断程序,调用python默认的异常处理器,并在终端输出异常信息。刚才举过的例子:int(“m”),便是解释器因为发现参数传入异常,这种异常解释器“无能为力”,所以它最后中断了程序,并将错误信息打印输出,告诉码农朋友们:你的程序有bug!!!

2、try…except…处理机制

  我们把可能发生错误的语句放在try语句里,用except来处理异常。每一个try,都必须至少有一个或者多个except。举一个最简单的例子如下,在try访问number的第500个元素,很明显数组越界访问不了,这时候解释器会发出异常信号:IndexError,接着寻找后面是否有对应的异常捕获语句except ,如果有则执行对应的except语句,待except语句执行完毕后,程序将继续往下执行。如果没有对应的except语句,即用户没有处理对应的异常,这时解释器会直接中断程序并将错误信息打印输出

number = &#39;hello&#39;try:	print(number[500])	#数组越界访问except IndexError:	print("下标越界啦!")except NameError:	print("未声明对象!")print("继续运行...")

输出结果如下,因为解释器发出异常信号是IndexError,所以执行下标越界语句。

下标越界啦!
继续运行...

  为了解锁更多用法,我们再将例子改一下,我们依然在try访问number的第500个元素,造成访问越界错误,这里的except用了as关键字可以获得异常对象,这样子便可获得错误的属性值来输出信息。

number = &#39;hello&#39;try:	print(number[500])	#数组越界访问except IndexError as e:	print(e)except Exception as e:	#万能异常
	print(e)except:			  	 #默认处理所有异常
	print("所有异常都可处理")print("继续运行...")

输出结果如下所示,会输出系统自带的提示错误:string index out of range,相对于解释器因为异常自己抛出来的一堆红色刺眼的字体,这种看起来舒服多了(能够“运筹帷幄”的异常才是好异常嘛哈哈哈)。另外这里用到“万能异常”Exception,基本所有没处理的异常都可以在此执行。最后一个except表示,如果没有指定异常,则默认处理所有的异常。

string index out of range继续运行...

3、try…except…finally…处理机制

  finally语句块表示,无论异常发生与否,finally中的语句都要执行完毕。也就是可以很霸气的说,无论产生的异常是被except捕获到处理了,还是没被捕获到解释器将错误输出来了,都统统要执行这个finally。还是原来简单的例子加上finally语句块如下,代码如下:

number = &#39;hello&#39;try:	print(number[500])	#数组越界访问,抛出IndexError异常except IndexError:	print("下标越界啦!")finally:	print("finally!")print("继续运行...")		#运行

结果如下,数据越界访问异常被捕获到后,先执行except 语句块,完毕后接着执行了finally语句块。因为异常被执行,所以后面代码继续运行。

下标越界啦!finally!
继续运行...

  对try语句块进行修改,打印abc变量值,因为abc变量没定义,所以会出现不会被捕获的NameError异常信号,代码如下所示:

number = &#39;hello&#39;try:	print(abc)	#变量未被定义,抛出NameError异常except IndexError:	print("下标越界啦!")finally:	print("finally!")print("继续运行...")	#不运行

结果如下,因为NameError异常信号没法被处理,所以解释器将程序中断,并将错误信息输出,但这过程中依然会执行finally语句块的内容。因为程序被迫中断了,所以后面代码不运行。

finally!	#异常没被捕获,也执行了finallyTraceback (most recent call last):
	File "E:/Test_code/test.py",line 3,in <module>
   		print("abc")NameError: name &#39;abc&#39; is not defined

  理解到这里,相信:try…finally…这种机制应该也不难理解了,因为省略了except 捕获异常机制,所以异常不可能被处理,解释器会将程序中断,并将错误信息输出,但finally语句块的内容依然会被执行。例子代码如下:

number = &#39;hello&#39;try:	print(abc)	#变量未被定义,抛出NameError异常finally:	print("finally!")print("继续运行...")

运行结果:

finally!	#异常没被捕获,也执行了finallyTraceback (most recent call last):
	File "E:/Test_code/test.py",line 3,in <module>
   		print("abc")NameError: name &#39;abc&#39; is not defined

4、assert断言处理机制

  assert语句先判断assert后面紧跟的语句是True还是False,如果是True则继续往下执行语句,如果是False则中断程序,将错误信息输出。

assert 1 == 1 	#为True正常运行assert 1 == 2	#为False,终止程序,错误信息输出

5、with…as处理机制

  with…as一般常用在文件处理上,我们平时在使用类似文件的流对象时,使用完毕后要调用close方法关闭,很麻烦,这里with…as语句提供了一个非常方便且人性的替代方法,即使突发情况也能正常关闭文件。举个例子代码如下,open打开文件后将返回的文件流对象赋值给fd,然后在with语句块中使用。

with open(&#39;e:/test.txt&#39;,&#39;r&#39;) as fd:
	fd.read()
	print(abc)	#变量未被定义,程序终止,错误信息输出print("继续运行...")

  正常情况下,这里的with语句块完毕之后,会自动关闭文件。但如果with语句执行中发生异常,如代码中的变量未定义异常,则会采用默认异常处理机制,程序终止,错误信息输出,后面代码不被运行,文件也会正常关闭。

三、python异常自定义

  说了这么多异常的使用,终于可以回到我前言所说的在实际项目中存在的问题,即错误码的返回和数值的返回是冲突的(因为错误码也是数值),这时候便可以用异常的抛出和捕获来完成错误码的传递,即try和except 。但系统发生异常时抛出的是系统本身定义好的异常类型,跟自己的错误码又有何关系?这就是我接下来要说的内容:如何定义自己的异常并且能够被except 所捕获

1、异常自定义

  实际开发中,有时候系统提供的异常类型往往都不能满足开发的需求。这时候就要使用到异常的自定义啦,你可以通过创建一个新的异常类来拥有自己的异常。自己定义的异常类继承自 Exception 类,可以直接继承,或者间接继承。栗子举起来:

class MyException(Exception):
    &#39;&#39;&#39;自定义的异常类&#39;&#39;&#39;
    def __init__(self, error_num):	#异常类对象的初始化属性
        self.error_num = error_num    def __str__(self):				#返回异常类对象说明信息
        err_info = [&#39;超时错误&#39;,&#39;接收错误&#39;]
        return err_info[self.error_num]

  该类继承自Exception 类,并且新类的名字为MyException,这跟前面我们一直在用的IndexError这个异常类一样,都是继承自Exception 类。__init__为构造函数,当我们创建对象时便会自动调用,__str__为对象说明信息函数,当使用print输出对象的时候,只要自己定义了__str__方法,那么就会打印从在这个方法中return的数据。
  即print(MyException(0))时,便可打印“超时错误”这个字符串,print(MyException(1))时,便可打印“接收错误”这个字符串,心细的你应该可以理解,MyException(x)为临时对象(x是传入错误码参数,这里只定义了0和1),与a = MyException(x),a为对象一个样子 。 这里有一个好玩的说法,在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法。

2、异常抛出raise

  现在我们自己定义的错误定义好了(上面的MyException),怎么能像IndexError一样让except捕获到呢?于是乎raise关键字派上用场。我们在异常机制中用try…except时,一般都是将可能产生的错误代码放到try语句块中,这时出现异常则系统便会自动将其抛出,比如IndexError,这样except就能捕获到,所以我们只要将自定义的异常在需要的时候将其抛出即可。
  raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类),那么我们刚刚定义的异常类就可以用啦,举个简单例子:

try:
    raise MyException(0)	# 自己定义的错误类,将错误码为0的错误抛出except MyException as e:
    print(e) 	  			# 输出的是__str__返回的内容,即“超时错误”

  这里我直接将自己定义的错误抛出,…as e就是把得到的错误当成对象e,这样才可以访问其属性和方法。因为自己定义的错误中可以支持多个错误码(本质还是MyException这个错误),所以便可实现传入不同错误码就可打印不同错误信息。

3、异常捕获

  只要我们在try中将错误raise出来,except就可以捕获到(当然,异常必须是Exception 子类才能被捕获),将前面两个例子整合起来,代码如下:

&#39;&#39;&#39;错误码:0代表超时错误,1代表接收错误&#39;&#39;&#39;class MyException(Exception):
    &#39;&#39;&#39;自定义的异常类&#39;&#39;&#39;
    def __init__(self, error_num):	# 异常类对象的初始化属性
        self.error_num= error_num    def __str__(self):				# 返回异常类对象指定错误码的信息
        err_info = [&#39;超时错误&#39;,&#39;接收错误&#39;]
        return err_info[self.error_num]def fun()
	raise MyException(1) 			# 抛出异常对象,传入错误码1def demo_main():
    try:
        fun()
    except MyException as ex:		# 这里要使用MyException进行捕获,对象为ex
        print(ex) 	   				# 输出的是__str__部分返回的内容,即“接收错误”
        print(ex.error_num) 		# 输出的是__init__中定义的error_num,即1demo_main()							#此处开始运行

  代码从demo_main函数开始执行,进入try语句块,语句块中的fun()函数模拟代码运行失败时raise 自定义的异常,except 正常接收后通过as 关键字得到异常对象,访问该异常对象,便可正常输出自定义的异常信息和自定义的错误码。

四、异常使用注意事项

此注意事项参考博文:异常机制使用细则.

1、不要太依赖异常机制

  python 的异常机制非常方便,对于信息的传递中十分好用(这里信息的传递主要有三种,参数传递,全局变量传递,以及异常机制传递),但滥用异常机制也会带来一些负面影响。过度使用异常主要表现在两个方面:①把异常和普通错误混淆在一起,不再编写任何错误处理代码,而是以简单地引发异常来代苦所有的错误处理。②使用异常处理来代替流程控制。例子如下:

buf = "hello"#例1:使用异常处理来遍历arr数组的每个元素try:
    i = 0    
    while True:
        print (buf [i])
        i += 1except:
    pass#例2:使用流程控制避免下标访问异常i = 0while i < len(buf ):
    print(buf [i])
    i += 1

  例1中假如循环过度便会下标访问异常,这时候把错误抛出,再进行一系列处理,显然是不可取的,因为异常机制的效率比正常的流程控制效率差,显然例2中简单的业务流程就可以避开这种错误。所以不要熟悉了异常的使用方法后,遇到这种简单逻辑,便不管三七二十一引发异常后再进行解决。对于完全己知的错误和普通的错误,应该编写处理这种错误的代码,增加程序的健壮性。只有对于外部的、不能确定和预知的运行时错误才使用异常

2、不要在 try 块中引入太多的代码

Placer beaucoup de code dans le bloc try semble "simple" et le cadre du code est facile à comprendre. Cependant, comme le code dans le bloc try est trop volumineux et que l'activité est trop complexe, cela provoquera. le code doit apparaître dans le bloc try. La possibilité d'anomalies est considérablement augmentée, ce qui rend plus difficile l'analyse des causes des anomalies.
 Et lorsque le bloc est trop grand, il est inévitable de faire suivre le bloc try avec un grand nombre de blocs except pour fournir une logique de traitement différente pour différentes exceptions. Si le même bloc try est suivi d'un grand nombre de blocs except, vous devez analyser la relation logique entre eux, ce qui augmente la complexité de la programmation. Par conséquent, vous pouvez diviser le grand bloc try en plusieurs petits blocs, puis intercepter et gérer les exceptions respectivement.

3. N'ignorez pas les exceptions détectées

  N'ignorez pas les exceptions ! Maintenant que l'exception a été interceptée, le bloc sauf devrait faire quelque chose d'utile et gérer et corriger l'exception . Il est inapproprié de laisser tout le bloc except vide, ou de simplement imprimer de simples informations sur les exceptions ! La méthode de gestion spécifique est la suivante :
Gérer les exceptions. Effectuez les réparations appropriées à l'exception, puis continuez à exécuter en contournant l'endroit où l'exception s'est produite ; ou utilisez d'autres données pour effectuer des calculs au lieu de la valeur de retour attendue de la méthode ou invitez l'utilisateur à réopérer. le programme doit essayer de réparer l'exception autant que possible. Autoriser le programme à reprendre son fonctionnement.
Re-lance une nouvelle exception. Faites autant que possible tout ce qui peut être fait dans l'environnement d'exécution actuel, puis traduisez l'exception, regroupez l'exception dans une exception de la couche actuelle et retransmettez-la à l'appelant de la couche supérieure.
Gérez les exceptions au niveau du calque approprié
. Si la couche actuelle ne sait pas comment gérer l'exception, n'utilisez pas l'instruction except dans la couche actuelle pour intercepter l'exception et laissez l'appelant de la couche supérieure être responsable de la gestion de l'exception.

Résumé

  Cet article commence par les exceptions par défaut du système, explique ce que sont les exceptions et résume les classes d'exceptions courantes dans le système, puis explique comment personnaliser les exceptions. De la définition des exceptions au lancement, en passant par la définition et l'utilisation des exceptions personnalisées, et résume enfin les précautions lors de l'utilisation des exceptions Python.

Recommandations d'apprentissage gratuites associées : Tutoriel Python(vidéo)

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer