简述python异常处理机制,python异常处理有何作用

  简述python异常处理机制,python异常处理有何作用

  在我之前的工作中,我使用python完成了一个命令行窗口,该窗口使用串口发送SCPI与单片机通信。实现功能的时候发现python返回的数据结果,不管是最终的正确值还是错误值,都可以直接返回到主界面。显然,直接返回不同含义的数据是不可能的,所以采用了异常机制来处理值错误的数据。因为之前不太了解异常,所以在这里查了一些资料,整理了一点笔记。

  

  文章目录

  一、对例外的理解1。什么是异常2,错误和异常的区别3。常见python异常的类型2。五种python异常处理机制1。默认异常处理机制2。尝试.除.之外.处理机制3。尝试.除.之外.最后.处理机制4。断言处理机制5,具有.as处理机制三、python异常定制1、异常定制2、异常抛出raise3、异常捕获4、异常使用注意事项1、不要过分依赖异常机制2、不要在try块引入过多代码3、不要忽略被捕获的异常总结。

  (免费学习推荐:python视频教程

  一、对异常的理解

  1、什么是异常

  即异常是“异于正常”。什么是正常?正常是指解释器解释代码时,我们写的代码符合解释器定义的规则,也就是正常。当解释器发现某段代码符合语法但有可能出现不正常的情况,时,解释器将发出一个事件来中断程序的正常执行。这个中断的信号是一个异常信号.所以,总体解释就是,在解释器发现到程序出现错误的时候,则会产生一个异常,若程序没有处理,则会将该异常抛出,程序的运行也随之终止.我们可以在空白处写一个int(“m”)。py文件,运行后的结果如下。

  这串字体是解释器抛出的一系列错误信息,因为int()传入的参数只支持数字串和数字。很明显,‘m’不属于参数传入的数值串的错误,所以解释器报出了“valueError”。

  2、错误和异常的区别

  python错误概述:它指的是代码运行前的语法或逻辑错误.以常规语法错误为例。当我们写的代码没有通过语法测试时,就会直接出现语法错误,必须在程序执行前纠正。否则写出来的代码就没有意义,代码就不会运行,也无法被捕获。例如,在中输入if a=1print ("hello ")。py文件,输出结果如下:

  回溯(最近呼叫):

  文件“E:/Test_code/test.py”,第1行

  如果a=1打印(“你好”)

  ^SyntaxError:无效语法函数print()被检查出有错误。它前面缺少一个冒号3360,所以解析器会重现有语法错误的那一行代码,并用一个小“箭头”指向该行中检测到的第一个错误,这样我们就可以直接找到相应的位置来修改它的语法。当然,除了语法错误之外,还有很多程序崩溃,比如内存溢出,这往往是隐藏的。

  与这个错误相比,此时的python异常主要在程序执行过程中,程序遇见逻辑或算法问题,如果翻译能处理好,那就好了。如果不能,就直接终止程序,抛出异常,比如第一个点的int(m m )的例子,因为参数传入错误,程序出错。有各种逻辑导致的例外。好在我们的解释器内置了各种异常,这样我们就能知道出现了什么样的异常,从而“对症下药”。

  这里注意,上面的语法错误是可以识别的错误,所以解释器也会默认抛出一个SyntaxError异常消息,并反馈给程序员。所以从本质上来说,大部分错误都是可以打印输出的,只是因为错误码没有运行,所以无法处理,所以捕捉错误的异常信息就变得没有意义了。

  3、常见python异常种类

  在这里,粘贴我们写代码时最常见的异常类型。如果遇到其他种类的例外,当然选择白度。

  啦~

  异常名称名称解析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 = 'hello'try:	print(number[500])	#数组越界访问except IndexError:	print("下标越界啦!")except NameError:	print("未声明对象!")print("继续运行...")
输出结果如下,因为解释器发出异常信号是IndexError,所以执行下标越界语句。

  

下标越界啦!

  继续运行...

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

  

number = 'hello'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 = 'hello'try:	print(number[500])	#数组越界访问,抛出IndexError异常except IndexError:	print("下标越界啦!")finally:	print("finally!")print("继续运行...")		#运行
结果如下,数据越界访问异常被捕获到后,先执行except 语句块,完毕后接着执行了finally语句块。因为异常被执行,所以后面代码继续运行。

  

下标越界啦!finally!

  继续运行...

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

  

number = 'hello'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 'abc' is not defined

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

  

number = 'hello'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 'abc' 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('e:/test.txt','r') as fd:

   fd.read()

   print(abc) #变量未被定义,程序终止,错误信息输出print("继续运行...")

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

  三、python异常自定义

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

  1、异常自定义

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

  

class MyException(Exception):

   '''自定义的异常类'''

   def __init__(self, error_num): #异常类对象的初始化属性

   self.error_num = error_num def __str__(self): #返回异常类对象说明信息

   err_info = ['超时错误','接收错误']

   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 子类才能被捕获),将前面两个例子整合起来,代码如下:

  

'''错误码:0代表超时错误,1代表接收错误'''class MyException(Exception):

   '''自定义的异常类'''

   def __init__(self, error_num): # 异常类对象的初始化属性

   self.error_num= error_num def __str__(self): # 返回异常类对象指定错误码的信息

   err_info = ['超时错误','接收错误']

   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 块中引入太多的代码

    在 try 块里放置大量的代码,这看上去很“简单”,代码框架很容易理解,但因为 try 块里的代码过于庞大,业务过于复杂,就会造成 try 块中出现异常的可能性大大增加,从而导致分析异常原因的难度也大大增加。
  而且当块过于庞大时,就难免在 try 块后紧跟大量的 except 块才可以针对不同的异常提供不同的处理逻辑。在同一个 try 块后紧跟大量的 except 块则需要分析它们之间的逻辑关系,反而增加了编程复杂度。所以,可以把大块的 try 块分割成多个小块,然后分别捕获并处理异常。

  3、不要忽略捕获到的异常

    不要忽略异常!既然己捕获到异常,那么 except 块理应做些有用的事情,及处理并修复异常。except 块整个为空,或者仅仅打印简单的异常信息都是不妥的!具体的处理方式为:
处理异常。对异常进行合适的修复,然后绕过异常发生的地方继续运行;或者用别的数据进行计算,以代替期望的方法返回值;或者提示用户重新操作,总之,程序应该尽量修复异常,使程序能恢复运行。
重新引发新异常。把在当前运行环境下能做的事情尽量做完,然后进行异常转译,把异常包装成当前层的异常,重新传给上层调用者。
在合适的层处理异常
。如果当前层不清楚如何处理异常,就不要在当前层使用 except 语句来捕获该异常,让上层调用者来负责处理该异常。

  总结

    本文从系统默认的异常起手,说明了什么是异常并总结了系统常见的异常类,接着写了怎么自定义异常,从异常的定义到抛出再到获取完成自定义异常的定义和使用,最后再总结了python异常使用时的注意事项。

  

相关免费学习推荐:python教程(视频)

  

以上就是读懂Python的异常机制的详细内容,更多请关注盛行IT软件开发工作室其它相关文章!

  

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • 常见的python异常及处理方法总结图,常见的python异常及处理方法总结论文
  • 常见的python异常及处理方法总结图,常见的python异常及处理方法总结图,常见的Python异常及处理方法总结
  • python异常值处理方法,python异常值检测常见方法
  • python异常处理过程可以概括为三个步骤,python处理异常有哪些方式
  • python如何实现对于数据中异常值的处理,python异常值检测
  • python异常处理中不会用到的关键字,python异常处理关键字
  • python异常处理判断是不是整数,python异常处理判断质数
  • python数据异常值的处理,python异常值处理方法
  • python异常处理方法,python异常处理有何作用
  • python处理异常的4种方式,python异常处理总结
  • Python异常处理机制,python针对异常的处理方式
  • python中异常处理的两种方式,python异常数据处理
  • 介绍一下python的异常处理机制,python异常处理实验报告
  • python异常和错误是同一概念吗-为什么-,python错误和异常处理
  • python异常值处理方法,python 异常值
  • 留言与评论(共有 条评论)
       
    验证码: