欢迎关注我的知乎账号
从字面上来看,异常是程序运行时出现的错误吧。
没错,每当在运行时检测到程序错误时,python就会引发异常。对待异常有两种方法:一是可以在程序中捕捉和响应错误;或者忽略已发生的异常。
如果是忽略已发生的异常,python默认的异常处理行为将启动:停止程序,打印出错消息。如果不想启动这种默认行为,就要写try语句来捕捉异常并从异常中恢复,当程序运行检测到错误时,python会跳到try处理器,而程序在try之后会重新继续执行。
首先来看看python自带的默认异常处理器
deffetcher(obj,index):returnobj[index]x=spamprint(fetcher(x,3))print(fetcher(x,9))mTraceback(mostrecentcalllast):File"E:/12homework/12homework.py",line7,in<module>print(fetcher(x,9))File"E:/12homework/12homework.py",line2,infetcherreturnobj[index]IndexError:stringindexoutofrange
从这个例子可以看到,我们试图对字符串末尾以后的位置做索引运算,当函数尝试执行obj[9]时,就会触发异常。Python会替序列检测到超出边界的索引运算,并通过抛出(触发)内置的IndexError异常进行报告。
在这个例子中,我们的代码没有刻意去捕捉这个异常,所以他会一直向上返回到程序顶层,并启用默认的异常处理器:就是打印标准出错信息,即异常发生时激活的程序行和函数清单。
那么,如果我们想自己去捕获异常呢?
因为在有些情况下,这并不是我们想要的。例如,服务器程序一般需要在内部发生错误时依然保持继续工作。如果你不想要默认的异常行为,就需要把调用封装在try语句内,自行捕捉异常。
deffetcher(obj,index):returnobj[index]x=spamtry:fetcher(x,9)exceptIndexError:print(got exception)gotexception
现在,当try代码块内程序执行触发异常时,python会自动跳至处理器(即except分句下面的代码块)去运行。
deffetcher(obj,index):returnobj[index]x=spamtry:fetcher(x,9)exceptIndexError:print(got exception)print(continue...)gotexceptioncontinue...
在这个例子中,我们在异常捕捉和处理后,程序在捕捉了整个try语句后继续执行;这就是我们之所以得到continue消息的原因。我们没有看见标准出错信息,而程序也将正常执行下去。
除了python自身会产生异常以外,我们在程序中也可以主动引发异常。想要手动触发异常,可以直接执行raise语句。用户通过raise触发的异常的捕捉方式和python程序自身引发的异常一样:
try:raiseIndexErrorexceptIndexError:print(got exception)gotexception
如果没有去捕捉到异常,用户定义的异常就会向上传递,直到顶层默认的异常处理器,并通过标准出错信息终止该程序,看看,是不是感觉很熟悉。
raiseIndexErrorTraceback(mostrecentcalllast):File"E:/12homework/12homework.py",line1,in<module>raiseIndexErrorIndexError
我们还可以自定义异常
刚才我们利用raise语句触发了python内置作用域中定义的一个内置异常。其实我们也可以自己定义一个新的异常,这里可能需要一点面向对象的知识,所以我们只需要了解即可:自定义的异常能够通过类来编写,它继承自一个内置的异常类:通常这个类的名称叫做Exception
classBad(Exception):passdefdoomed():raiseBad()try:doomed()exceptBad:print(got Bad)gotBad
最后说说终止行为finally代码块
try语句可以包含finally代码块。可以定义一定会在最后执行时的收尾行为。这里的一定指的是无论try代码块中是否发生了异常都会执行。
try:raiseIndexErrorfinally:print(in finally)print(after finally)infinallyTraceback(mostrecentcalllast):File"E:/12homework/12homework.py",line2,in<module>raiseIndexErrorIndexErrortry:print(ok)finally:print(in finally)print(after finally)okinfinallyafterfinally
可以看出,上述try/finally语句组合,无论try代码块是否发生异常,程序都将会执行finally代码块中的语句。但是当有异常发生时,python会跳过去执行finally中的行为,执行完finally中的语句后,再将try中的异常传递给顶层的默认处理器,因此finally后面的语句就不会执行了。但是如果try中的代码不触发异常,则finally后面的代码块就会正常的继续执行。
我们总结一下:
在实际应用中,try/except的组合可用于捕捉异常并从中恢复,而try/finally的组合则很方便,可以确保无论try代码块内的代码是否发生了异常,终止行为都一定会运行。
一个例子是:比如无论是否出现异常,无论异常是否被捕获,都一定会确保关闭文件。
最终我们是可以把try/except/finally三者连用的,try内为主体功能代码,except用来捕获异常,而无论异常是否出现,是否被except捕获,都将执行finally内的语句。
我来详细介绍异常编码的语法模式,try/except/else和try/finally。
先重新总结回顾一下try、except、else、finally几个关键字:
try后面紧跟着缩进的语句代码,代表此语句的主要动作:试着执行的程序代码。
然后是一个或多个except分句来识别要捕获的异常,except子句内定义try代码块内引发的异常处理器,
最后是一个可选的else分句,提供没发生异常时要执行的语句。
分别讨论下面的几种情形:
如果try代码块语句执行时的确发生了异常,python就跳出try,执行第一个符合引发异常的except子句下面的语句。当except代码块执行结束后,控制权就会到整个try代码块后继续执行。
如果异常发生在try代码块内,没有符合的except子句,异常就会传递到顶层,迫使python终止这个程序并打印默认的出错信息。
如果try首行底下执行的语句没有发生异常,python就会执行else行下的语句,控制权会在整个try语句下继续。
换句话说,except分句会捕获try代码块执行时所发生的异常,而else子句只在try代码块执行时不发生异常才会执行。
except是专注于异常处理器的:捕捉只在相关try代码块中的语句所发生的异常。尽管这样,因为try代码块语句可以调用写在程序其他地方的函数,异常的来源可能在try语句自身之外。
关于except子句的一些说明:
except子句可以用括号列出一组异常[except (e1,e2,e3)],而如果except子句后没有列出异常名称,即except:时,会捕捉所有的异常类型。
但是,空except也会引发一些设计的问题,尽管方便,也可能捕捉和程序代码无关、意料之外的系统异常,而且可能意外拦截其他处理器的异常。例如,在python中,即使是系统离开调用,也会触发异常,而显然你通常会想让这些事件通过。
python引入了一个替代方案来解决这个问题,捕获一个名为Exception的异常,几乎与一个空的except:具有相同的效果,但是忽略和系统退出相关的异常。
来看看try/else语句的作用
也许我们无法一眼看出else子句的用途,不过仔细想想,如果没有else,是无法知道控制流程是否通过了try语句,到底是没有异常引发,还是异常发生了且已被处理过了,不使用else的话很难分得清。
再来分析一下try/finally语句
try中包含了finally子句,python一定会在try语句后执行其语句代码块,无论try代码块执行时是否发生异常。
利用这个变体,python可先执行try首行下的语句代码块。接下来发生的事情,取决于代码块中是否发生异常:
如果try代码块运行时没有异常发生,python会跳至执行finally代码块,然后在整个try语句后继续执行下去。
如果try代码块运行时有异常发生,python依然会回来运行finally代码块,但是接着会把异常向上传递到较高的try语句或顶层的默认异常处理器,程序不会在try语句下继续执行。也就是说,即使发生了异常,finally代码块还是会执行的,和except不同的是,finally不会终止异常,而是在finally代码块执行后,抛出异常。
当想确定某些程序代码执行后,无论程序的异常行为如何,有个动作一定会发生,那么,try/finally形式就很有用。在实际应用中,这可以让你定义一定会发生的清理动作,最直观的就是,在出现异常时,仍能利用finally关闭文件和断开服务器连接。
最后我们来看最完整的形式:try/except/else/finally
try:main-actionexceptException1:handler1exceptException2:handler2...else:else-blockfinally:finally-block
我们从头梳理一遍:
就像往常一样,这个语句中的main-action代码会先执行。如果该程序代码引发异常,那么所有except代码块就会逐一测试,寻找与抛出的异常相符的语句,如果引发的异常是Exception1,就会执行handler1,如果引发的的异常是Exception2,就会执行handler2,以此类推,如果没有引发任何异常,将会执行else-block。而无论之前发生了什么,当main-action代码块完成的时候,而任何引发的异常都已经处理后,finally-block就会执行。事实上,即使异常处理器或者else-block内有错误发生而引发新的异常,finally-block内的程序代码依然会执行。就像之前所说的那样,finally子句并没有终止异常:当finally-block执行的时候,如果异常还存在,就会在finally-block代码块执行后继续传递,而控制权会跳至程序其他地方,如我们的默认的顶层处理器。
最后我们叮嘱一下,try语句必须有一个except或一个finally,else是可选的,但是如果有else,则必须至少有一个except。
关于Python编程和数据分析更全面的内容,欢迎关注我在CSDN上的专栏《python数据分析编程基础》。
当然还有《机器学习中的数学-全集(python版)》系列专栏,欢迎大家阅读,配合食用,效果更佳~
有订阅的问题可咨询微信:zhangyumeng0422
声明:本文部分素材转载自互联网,如有侵权立即删除 。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容