- 译者序
- 前言
- 第1章 问答环节
- 第2章 Python 如何运行程序
- 第3章 如何运行程序
- 第4章 介绍 Python 对象类型
- 第5章 数字
- 第6章 动态类型简介
- 第7章 字符串
- 第8章 列表与字典
- 第9章 元组、文件及其他
- 第10章 Python 语句简介
- 第11章 赋值、表达式和打印
- 第12章 if 测试和语法规则
- 第13章 while 和 for 循环
- 第14章 迭代器和解析,第一部分
- 第15章 文档
- 第16章 函数基础
- 第17章 作用域
- 第18章 参数
- 第19章 函数的高级话题
- 第20章 迭代和解析,第二部分
- 第21章 模块:宏伟蓝图
- 第22章 模块代码编写基础
- 第23章 模块包
- 第24章 高级模块话题
- 第25章 OOP:宏伟蓝图
- 第27章 更多实例
- 第28章 类代码编写细节
- 第29章 运算符重载
- 第30章 类的设计
- 第31章 类的高级主题
- 第32章 异常基础
- 第34章 异常对象
- 第35章 异常的设计
- 第36章 Unicode 和字节字符串
- 字符串基础知识
- Python 的字符串类型
- 文本和二进制文件
- Python 3.0 中的字符串应用
- 转换
- 编码 Unicode 字符串
- 编码非ASCII文本
- 编码和解码非ASCII文本
- 其他 Unicode 编码技术
- 转换编码
- 在 Python 2.6 中编码 Unicode 字符串
- 源文件字符集编码声明
- 使用 Python 3.0 Bytes 对象
- 序列操作
- 创建 bytes 对象的其他方式
- 混合字符串类型
- 使用 Python 3.0(和 Python 2.6)bytearray 对象
- 使用文本文件和二进制文件
- Python 3.0 中的文本和二进制模式
- 类型和内容错误匹配
- 使用 Unicode 文件
- 在 Python 3.0 中处理 BOM
- Python 2.6 中的 Unicode 文件
- Python 3.0 中其他字符串工具的变化
- Struct二进制数据模块
- pickle对象序列化模块
- XML解析工具
- 本章小结
- 本章习题
- 习题解答
- 第37章 管理属性
- 第38章 装饰器
- 第39章 元类
- 附录A 安装和配置
- 附录B 各部分练习题的解答
- 作者介绍
- 封面介绍
第35章 异常的设计
嵌套异常处理器
到目前为止,我们的例子都只使用了单一的try语句来捕捉异常,如果try中还有try,那会发生什么事情呢?就此而言,如果try调用一个会执行另一个try的函数,这代表了什么意思呢?从技术角度上来讲,从语法和代码运行时的控制流程来看,try语句是可以嵌套的。
如果你知道Python会在运行时将try语句放入堆栈,这两种情况就可以理解了。当发生异常时,Python会回到最近进入、具有相符except分句的try语句。因为每个try语句都会留下标识,Python可检查堆栈的标识,从而跳回到较早的try。这种处理器的嵌套化,就是我们所谈到的异常向上传递至较高的处理器的意思:这类处理器就是在程序执行流程中较早进入的try语句。
图35-1说明嵌套的try/except语句在运行时所发生的事情。进入try代码块的代码量可能很大(例如,它可能包含了函数调用),而且通常会启用正在监视相同异常的其他代码。当异常最终引发时,Python会跳回到匹配该异常、最近进入的try语句,执行该语句的except分句,然后在try语句后继续下去。
一旦异常被捕捉,其生命就结束:控制权不会跳回所有匹配这个异常、相符的try语句;只有第一个try有机会对它进行处理。如图35-1所示,函数func2中的raise语句会把控制权返还func1中的处理器,然后程序再在func1中继续下去。
图 35-1 嵌套的try/except语句:当异常引发时(由你或由Python引起),控制权会跳回具有相符的except子句、最近进入的try语句,而程序会在try语句后继续执行下去。except子句会拦截并停止异常,这里就是你处理异常并从中恢复的地方
与之相对比的是,当try/finally语句嵌套且异常发生时,每个finally代码块都会执行:Python会持续把异常往上传递到其他try语句上,而最终可能达到顶层默认处理器(标准出错消息打印器)。如图35-2所示,finally子句不会终止异常,而是指明异常传播过程中,离开每个try语句之前要执行的代码。如果异常发生时,有很多try/finally都在活动,它们就都会运行,除非有个try/except在这个过程中捕捉某处该异常。
图 35-2 嵌套的try/finally:当异常在这里引发时,控制权会回到最近进入的try去执行其finally语句,异常会持续传播到所有激活状态下try语句的finally,直到最终抵达默认顶层处理器,在那里打印出错消息。Finally子句会拦截(但不会停止)异常:只是定义了离开前要执行的动作而已
换句话说,引发异常时,程序去向何方完全取决于异常在何处发生:这是脚本运行时控制流程的函数,而不仅仅是其语法。异常的传递,基本上就是回到处理先前进入但尚未离开的try。只要控制权碰到相符except子句,传递就会停止,而通过finally子句时就不会。
例子:控制流程嵌套
让我们分析一个例子,让这个嵌套的概念更为具体。下面的模块文件nestexc.py定义了两个函数。action2是写成要触发异常(做数字和序列的加法),而action1把action2调用封装在try处理器内,以捕捉异常。
那么,文件底端的顶层模块代码,也在try处理器中包装了action1调用。当action2触发TypeError异常时,就有两个激活的try语句:一个在action1内,另一个在模块文件顶层。Python会挑选并执行具有相符except、最近的try,而在这个例子中就是action1中的try。
正如我所提到过的,异常最后的所在之处,取决于程序运行时的控制流程。因此,想要知道你要去哪里,就需要知道你在哪里。就这个例子而言,异常在哪里进行处理是控制流程的函数,而不是语句的语法。然而,我们也可以用语法把异常处理器嵌套化——等一下会看与其等效的情况。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论