内容概要
内容详细 什么是异常 异常是程序发生错误的信号
程序一旦出现错误,便会产生一个异常,若程序中没有处理它,就会抛出该异常,程序的运行也随之终止
1 2 3 4 5 6 7 8 9 而错误分为两种: 1 是语法上的错误syntaxerror,这种错误应该在程序运行前就修改正确>>> if File "<stdin>" , line 1 if ^ SyntaxError: invalid syntax
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 2 是逻辑错误,常见的逻辑错误如:1 +’2 ’num=input (">>: " ) int (num)x l=['egon' ,'aa' ] l[3 ] dic={'name' :'egon' } dic['age' ] class Foo : pass Foo.x 1 /0
异常处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 为了保证程序的容错性与可靠性 ---> 在遇到错误时有相应的处理机制不会任由程序崩溃 ---> 需要对异常进行处理 处理的基本形式为: try : 被检测的代码块 except 异常类型 检测到异常,就执行这个位置的逻辑 例如: try : print ('start...' ) print (x) print ('end...' ) except NameError as e: print ('异常值为:%s' %e) print ('run other code...' )start... 异常值为:name 'x' is not defined run other code...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ======================================================================================== 本来程序一旦出现异常即整体结束掉了,但有了异常处理以后: 在被检测的代码块出现异常时: 1 被检测的代码块中异常发生位置之后的代码将不会继续执行 2 取而代之的是执行匹配异常的except 子代码块,其余代码均正常运行 当被检测的代码块中有可能触发不同类型的异常时,针对不同类型的异常: 如果我们想分别用不同的逻辑处理,则需要用到多分支的except (类似于多分支的elif ,从上到下依次匹配,匹配成功依次便不再匹配其他) try : 被检测的代码块 except NameError: 触发NameError时对应的处理逻辑 except IndexError: 触发IndexError时对应的处理逻辑 except KeyError: 触发KeyError时对应的处理逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 例如: def convert_int (obj ): try : res=int (obj) except ValueError as e: print ('ValueError: %s' %e) res=None except TypeError as e: print ('TypeError: %s' %e) res=None return res convert_int('egon' ) convert_int({'n' :1 })
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ======================================================================================== 如果想多种类型的异常统一用一种逻辑处理,可以将多个异常放到一个元组内,用一个except 匹配 try : 被检测的代码块 except (NameError,IndexError,TypeError): 触发NameError或IndexError或TypeError时对应的处理逻辑 例如: def convert_int (obj ): try : res=int (obj) except (ValueError,TypeError): print ('argument must be number or numeric string' ) res=None return res convert_int('egon' ) convert_int({'n' :1 })
1 2 3 4 5 6 7 8 9 10 如果我们想捕获所有异常并用一种逻辑处理,Python提供了一个万能异常类型Exception try : 被检测的代码块 except NameError: 触发NameError时对应的处理逻辑 except IndexError: 触发IndexError时对应的处理逻辑 except Exception: 其他类型的异常统一用此处的逻辑处理
1 2 3 4 5 6 7 8 9 10 11 12 13 ======================================================================================== 在多分支except 之后还可以跟一个else (else 必须跟在except 之后,不能单独存在),只有在被检测的代码块没有触发任何异常的情况下才会执行else 的子代码块 try : 被检测的代码块 except 异常类型1 : pass except 异常类型2 : pass ...... else : 没有异常发生时执行的代码块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 此处try 还可以与finally 连用,从语法上讲finally 必须放到else 之后, 但可以使用try -except -finally 的形式, 也可以直接使用try -finally 的形式 无论被检测的代码块是否触发异常,都会执行finally 的子代码块 ---> 因此通常在finally 的子代码块做一些回收资源的操作,比如关闭打开的文件、关闭数据库连接... try : 被检测的代码块 except 异常类型1 : pass except 异常类型2 : pass ...... else : 没有异常发生时执行的代码块 finally : 无论有无异常发生都会执行的代码块
1 2 3 4 5 6 7 8 9 10 11 例如: f=None try : f=open (‘db.txt’,'r' ,encoding='utf-8' ) s=f.read().strip() int (s) finally : if f: f.close()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 在不符合python解释器的语法或逻辑规则时,是由python解释器主动触发的各种类型的异常,而对于违反程序员自定制的各类规则,则需要由程序员自己来明确地触发异常,这就用到了raise 语句,raise 后必须是一个异常的类或者是异常的实例 class Student : def __init__ (self,name,age ): if not isinstance (name,str ): raise TypeError('name must be str' ) if not isinstance (age,int ): raise TypeError('age must be int' ) self.name=name self.age=age stu1=Student(4573 ,18 ) stu2=Student('egon' ,'18' )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 在内置异常不够用的情况下,我们可以通过继承内置的异常类来自定义异常类 class PoolEmptyError (Exception ): def __init__ (self,value='The proxy source is exhausted' ): super (PoolEmptyError,self).__init__() self.value=value def __str__ (self ): return '< %s >' %self.value class NetworkIOError (IOError ): pass raise PoolEmptyError raise NetworkIOError('连接被拒绝' )
1 2 3 4 5 6 7 8 9 10 11 最后,python还提供了一种'断言语句' assert expression,断定表达式expression成立,否则触发异常AssertionError,与raise -if -not 的语义相同,如下 age='18' assert isinstance (age,int )if not isinstance (age,int ): raise AssertionError
何时使用异常处理 1 2 3 4 5 6 7 8 9 10 11 在了解了异常处理机制后,本着提高程序容错性和可靠性的目的,可能会错误的认为应该尽可能地为程序加上try ...except ... 这其实是在过度消费程序的可读性,因为try ...except 本来就是你附加的一种额外的逻辑,与你的主要工作时没有多大关系的 如果错误发生的条件是 '可预知的' ,我们应该用if 来进行'预防' ,如下 age=input ('input your age>>: ' ).strip() if age.isdigit(): age=int (age) else : print ('You must enter the number' )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 如果错误发生的条件是'不可预知的' ,即异常一定会触发,那么我们才应该使用try ...except 语句来处理 例如编写一个下载网页内容的功能,网络发生延迟之类的异常是很正常的事,而我们根本无法预知在满足什么条件的情况下才会出现延迟,因而只能用异常处理机制了 import requestsfrom requests.exceptions import ConnectTimeout def get (url ): try : response=requests.get(url,timeout=3 ) res=response.text except ConnectTimeout: print ('连接请求超时' ) res=None except Exception: print ('网络出现其他异常' ) res=None return res get('https://www.python.org' )