返回介绍

第33章 异常编码细节

发布于 2024-01-29 22:24:15 字数 3795 浏览 0 评论 0 收藏 0

在前一章中,我们快速地浏览了与异常相关的语句。这里,我们将深入一点介绍——本章针对Python中的异常处理语法给出了更正式一些的介绍。特别是,我们将介绍try、raise、assert和with语句背后的细节。正如我们将看到的,尽管这些语句大多比较简单,但它们提供了强大的工具来处理Python代码中的异常。

注意:此前的一点常规提示是:异常的内容近年来有了一些变化。从Python 2.5起,finally子句可以同样出现在try语句以及except和else语句中(此前,它们不能组合)。此外,从Python 3.0和Python 2.6开始,新的with环境管理器语句成为正式的,并且用户定义的异常现在必须编写为类实例。此外,Python 3.0支持raise语句和except子句的略微修改的语法。我们将在本书这一版本中关注Python 2.6和Python 3.0中的异常状态,但是,由于你仍然很可能在代码中看到最初的技术,因此,一路上我们会指出在此领域中有哪些发展变化。

try/except/else语句

既然了解了基础的知识,让我们来看一些细节。下列讨论中,本书把try/except/else和try/finally当成独立的语句进行介绍,因为它们是不同角色,在Python 2.5以前都无法合并。就像你所见到的一样,在Python 2.5中,except和finally可以混在一个try语句中。分别探索过这两种原始形式后,再说明这种改变的含义。

try是复合语句,它的最完整的形式如下所示。首先是以try作为首行,后面紧跟着(通常)缩进的语句代码,然后是一个或多个except分句来识别要捕捉的异常,最后是一个可选的else分句。try、except以及else这些关键字会缩进在相同的层次(也就是垂直对齐)。为了方便参考,以下是其在Python 3.0中的一般格式。

在这个语句中,try首行底下的代码块代表此语句的主要动作:试着执行的程序代码。Except子句定义try代码块内引发的异常的处理器,而else子句(如果编写了的话)则是提供没发生异常时要执行的处理器。在这里的<data>元素和raise语句功能有关,本章稍后会进行讨论。

以下是try语句的运行方式。当try语句启动时,Python会标识当前的程序环境,这样一来,如果有异常发生时,才能返回这里。try首行下的语句会先执行。接下来会发生什么事情,取决于try代码块语句执行时是否引发异常。

·如果try代码块语句执行时的确发生了异常,Python就跳回try,执行第一个符合引发异常的except子句下面的语句。当except代码块执行后(除非except代码块引发了另一异常),控制权就会到整个try语句后继续执行。

·如果异常发生在try代码块内,没有符合的except子句,异常就会向上传递到程序中的之前进入的try中,或者如果它是第一条这样的语句,就传递到这个进程的顶层(这会使Python终止这个程序并打印默认的出错消息)。

·如果try首行底下执行的语句没有发生异常,Python就会执行else行下的语句(如果有的话),控制权会在整个try语句下继续。

换句话说,except分句会捕捉try代码块执行时所发生的任何异常,而else子句只在try代码块执行时不发生异常才会执行。

except子句是专注于异常处理器的:捕捉只在相关try代码块中的语句所发生的异常。尽管这样,因为try代码块语句可以调用写在程序其他地方的函数,异常的来源可能在try语句自身之外。第35章探索try嵌套化时,会再多介绍一些关于这方面的内容。

try语句分句

编写try语句时,有一些分句可以在try语句代码块后出现。表33-1列出所有可能形式:至少会使用其中一种。本书已经介绍过一些表33-1列出的形式:正如你所知道的那样,except分句会捕捉异常,finally分句最后一定会执行,而如果没遇上异常,else分句就会执行。

从语法上来讲,except分句数目没有限制,但是应该只有一个else。在Python2.4中,finally必须单独出现(没有else或except),其实这是不同的语句。然而,从Python 2.5开始,finally可出现在except和else所在的同一个try语句中了(在本章中,当我们遇到统一的try语句的时候,还会更多地讨论排序规则)。

当我们见到raise语句时,就会探索具有额外数据的部分。它们提供了对作为异常引发的对象的访问。

表33-1中第一和第四项是新的。

·except子句没列出异常名称(except:)时,捕捉没在try语句内预先列出的所有异常。

·except子句以括号列出一组异常[except(e1,e2,e3):]会捕捉所列出的任何异常。

因为Python会从头到尾检查except子句,在某个try中寻找是否有相符者,所以括号版本就像是每个异常列在其except子句内,但是语句主体只需编写一次而已。以下是多个except子句的例子,示范处理器的具体化。

在这个例子中,如果action函数执行时,引发了异常,Python会回到try,并搜索第一个和异常名称相符的except。Python会从头到尾以及由左至右查看except子句,然后执行第一个相符的except下的语句。如果没有符合的,异常会向这个try外传递。注意:只有当action中没有发生异常时,else才会执行,当没有相符except的异常发生时,则不会执行。

如果想要编写通用的“捕捉一切”分句,空的except就可以做到。

空的except子句是一种通用功能:因为这是捕捉任何东西,可让处理器通用化或具体化。在某些场合下,比起列出的try中所有可能异常来说,这种形式反而更方便一些。例如,下面是捕捉一切,但没列出任何事件的例子。

不过,空except也会引发一些设计的问题:尽管方便,也可能捕捉和程序代码无关、意料之外的系统异常,而且可能意外拦截其他处理器的异常。例如,在Python中,即便是系统离开调用,也会触发异常,而你通常会想让这些事件通过。这一部分末尾会再谈这个陷阱。就目前而言,要小心使用。

Python 3.0引入了一个替代方案来解决这些问题之一——捕获一个名为Exception的异常几乎与一个空的except具有相同的效果,但是,忽略和系统退出相关的异常:

这与空的except具有大多相同的便利性,但是,几乎同样具有危险性。我们将在下一章介绍这种形式如何发挥其魔力,在我们学习异常类的时候。

注意:版本差异提示:Python 3.0要求表33-1中列出的except E as V:处理器子句形式,并且本书中使用该形式,而不是旧的except E,V:形式。后一种形式在Python 2.6中仍然可用(但是不推荐使用):如果使用它,它将会转换为前者。做出这一改变,是剔除把旧的形式与两种替代的异常搞混淆的错误,这两种替代形式在Python 2.6中相应地编码为except(E1,E2):。由于Python 3.0只支持as形式,不管是否使用圆括号,值都会解释为替代的异常以供捕获。这一修改还改变了作用域规则:使用新的as语法,变量V在except语句块的末尾删除。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文