《Python基础教程(第3版)》笔记:第8章异常
《Python基础教程(第3版)》笔记:异常
重点
第8章 异常
异常对象未被处理(或捕获)时,程序将终止并显示一条错误信息:traceback
每个异常都是某个类的实例,
如何创建异常
如何自主引发异常:raise
raise Exception
raise Exception('hyperdrive overload')
一些内置的异常类
类名 描述 Exception 几乎所有的异常类都是从它派生而来的 AttributeError 引用属性或给它赋值失败时引发 OSError 操作系统不能执行指定的任务(如打开文件)时引发,有多个子类 IndexError 使用序列中不存在的索引时引发,为LookupError的子类 KeyError 使用映射中不存在的键时引发,为LookupError的子类 NameError 找不到名称(变量)时引发 SyntaxError 代码不正确时引发 TypeError 将内置操作或函数用于类型不正确的对象时引发 ValueError 将内置操作或函数用于这样的对象时引发:其类型正确但包含的值不合适 ZeroDivisionError 在除法或求模运算的第二个参数为零时引发 自定义异常类:务必直接或间接地继承Exception
class SomeException(Exception): pass
如何处理异常
捕获异常
try/except
, 异常从函数向外传播到调用函数的地方,如果在这里也没有被捕获,异常将继续向程序的最顶层传播。导致进入except子句的异常将被作为异常上下文存储起来
多个except子句
使用一个except子句捕获多种异常,可在一个元组中指定这些异常
try:x = int(input('value1:'))y = int(input('value2:'))print(x/y) except (ZeroDivisionError, TypeError, NameError):print('your numbers were bogus...')
下面的代码,捕获所有异常,当不存在异常时,终止循环
while True:try:x = int(input('value1:'))y = int(input('value2:'))print(x/y)except Exception as e:print('your numbers were bogus...', e)else:break
- finally子句,可用于在发生异常时执行清理工作
例子
def describe_person(person):print('Description of ', person['name'])print('Age: ', person['age'])try:print('Occupation:', person['occupation'])except KeyError: pass
try:obj.write except AttributeError:print('The object is not writeable') else:print('the object is writeable')
编写计算机程序时,通常能够区分正常和异常(不正常)情况。异常事件可能是错误(如试图除以零),也可能是通常不会发生的事情。为处理这些异常事件,可在每个可能发生这些事件的地方都使用条件语句。例如,对于每个除法运算,都检查除数是否为零。然而,这样做不仅效率低下、缺乏灵活性,还可能导致程序难以卒读。你可能很想忽略这些异常事件,希望它们不会发生,但Python提供功能强大的替代解决方案——异常处理机制。
8.1 异常是什么
Python使用异常对象来表示异常状态,并在遇到错误时引发异常。异常对象未被处理(或捕获)时,程序将终止并显示一条错误消息(traceback)。
>>> 1 / 0
Traceback (most recent call last): File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
每个异常都是某个类(这里是ZeroDivisionError)的实例。你能以各种方式引发和捕获这些实例,从而逮住错误并采取措施,而不是放任整个程序失败
8.2 让程序沿着你指定的轨道出错
正如你看到的,出现问题时,将自动引发异常。先来看看如何自主地引发异常,还有如何创建异常,然后再学习如何处理这些异常。
8.2.1 raise 语句
要引发异常,可使用raise语句,并将一个类(必须是Exception的子类)或实例作为参数。将类作为参数时,将自动创建一个实例。下面的示例使用的是内置异常类Exception:
>>> raise Exception
Traceback (most recent call last):File "<pyshell#15>", line 1, in <module>raise Exception
Exception
>>> raise Exception('hyperdrive overload')
Traceback (most recent call last):File "<pyshell#16>", line 1, in <module>raise Exception('hyperdrive overload')
Exception: hyperdrive overload
表8-1 一些内置的异常类
类 名 | 描 述 |
---|---|
Exception | 几乎所有的异常类都是从它派生而来的 |
AttributeError | 引用属性或给它赋值失败时引发 |
OSError | 操作系统不能执行指定的任务(如打开文件)时引发,有多个子类 |
IndexError | 使用序列中不存在的索引时引发,为LookupError的子类 |
KeyError | 使用映射中不存在的键时引发,为LookupError的子类 |
NameError | 找不到名称(变量)时引发 |
SyntaxError | 代码不正确时引发 |
TypeError | 将内置操作或函数用于类型不正确的对象时引发 |
ValueError | 将内置操作或函数用于这样的对象时引发:其类型正确但包含的值不合适 |
ZeroDivisionError | 在除法或求模运算的第二个参数为零时引发 |
8.2.2 自定义的异常类
那么如何创建异常类呢?就像创建其他类一样,但务必直接或间接地继承Exception(这意味着从任何内置异常类派生都可以)。因此,自定义异常类的代码类似于下面这样:
class SomeCustomException(Exception): pass
8.3 捕获异常
异常比较有趣的地方是可对其进行处理,通常称之为捕获异常。为此,可使用try/except语句。
try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y)
except ZeroDivisionError: print("The second number can't be zero!")
注意 异常从函数向外传播到调用函数的地方。如果在这里也没有被捕获,异常将向程序的最顶层传播。这意味着你可使用try/except来捕获他人所编写函数引发的异常。有关这方面的详细信息,请参阅8.4节。
8.3.1 不用提供参数
捕获异常后,如果要重新引发它(即:继续向上传播),可调用raise且不提供任何参数(也可显式地提供捕获到的异常,参见8.3.4节)
为说明这很有用,来看一个能够“抑制”异常ZeroDivisionError的计算器类。如果启用了这种功能,计算器将打印一条错误消息,而不让异常继续传播。在与用户交互的会话中使用这个计算器时,抑制异常很有用;但在程序内部使用时,引发异常是更佳的选择(此时应关闭“抑制”功能)。下面是这样一个类的代码:
class MuffledCalculator: muffled = False def calc(self, expr): try: return eval(expr) except ZeroDivisionError: if self.muffled: print('Division by zero is illegal') else: raise
注意 发生除零行为时,如果启用了“抑制”功能,方法calc将(隐式地)返回None。换而言之,如果启用了“抑制”功能,就不应依赖返回值。
下面的示例演示了这个类的用法(包括启用和关闭了抑制功能的情形):
>>> calculator = MuffledCalculator()
>>> calculator.calc('10 / 2')
5.0
>>> calculator.calc('10 / 0') # 关闭了抑制功能
Traceback (most recent call last): File "<stdin>", line 1, in ? File "MuffledCalculator.py", line 6, in calc return eval(expr) File "<string>", line 0, in ?
ZeroDivisionError: integer division or modulo by zero
>>> calculator.muffled = True
>>> calculator.calc('10 / 0')
Division by zero is illegal
如你所见,关闭抑制功能时,捕获了异常ZeroDivisionError,但继续向上传播它。
如果无法处理异常,在except子句中使用不带参数的raise通常是不错的选择,但有时你可能想引发别的异常。在这种情况下,导致进入except子句的异常将被作为异常上下文存储起来,并出现在最终的错误消息中,如下所示
>>> try:
... 1/0
... except ZeroDivisionError:
... raise ValueError
...
Traceback (most recent call last): File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero
在处理上述异常时,引发了另一个异常:
Traceback (most recent call last): File "<stdin>", line 4, in <module>
ValueError
你可使用raise … from …语句来提供自己的异常上下文,也可使用None来禁用上下文。
>>> try:
... 1/0
... except ZeroDivisionError:
... raise ValueError from None
...
Traceback (most recent call last): File "<stdin>", line 4, in <module>
ValueError
8.3.2 多个except子句
如果你运行前一节的程序,并在提示时输入一个非数字值,将引发另一种异常。
Enter the first number: 10
Enter the second number: "Hello, world!"
Traceback (most recent call last): File "exceptions.py", line 4, in ? print(x / y)
TypeError: unsupported operand type(s) for /: 'int' and 'str'
由于该程序中的except子句只捕获ZeroDivisionError异常,这种异常将成为漏网之鱼,导致程序终止。为同时捕获这种异常,可在try/except语句中再添加一个except子句。
try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y)
except ZeroDivisionError: print("The second number can't be zero!")
except TypeError: print("That wasn't a number, was it?")
8.3.3 一箭双雕
如果要使用一个except子句捕获多种异常,可在一个元组中指定这些异常,如下所示:
try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y)
except (ZeroDivisionError, TypeError, NameError): print('Your numbers were bogus ...')
在上述代码中,如果用户输入字符串、其他非数字值或输入的第二个数为零,都将打印同样的错误消息。当然,仅打印错误消息帮助不大。另一种解决方案是不断地要求用户输入数字,直到能够执行除法运算为止,8.3.6节将介如何这样做。
在except子句中,异常两边的圆括号很重要。一种常见的错误是省略这些括号,这可能导致你不想要的结果,其中的原因请参阅下一节
8.3.4 捕获对象
要在except子句中访问异常对象本身,可使用两个而不是一个参数。(请注意,即便是在你捕获多个异常时,也只向except提供了一个参数——一个元组。)需要让程序继续运行并记录错误(可能只是向用户显示)时,这很有用。下面的示例程序打印发生的异常并继续运行:
try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y)
except (ZeroDivisionError, TypeError) as e: print(e)
在这个小程序中,except子句也捕获两种异常,但由于你同时显式地捕获了对象本身,因此可将其打印出来,让用户知道发生了什么情况。8.3.6节将介绍这种技术的另一种更有用的用途。
8.3.5 一网打尽
即使程序处理了好几种异常,还是可能有一些漏网之鱼。例如,对于前面执行除法运算的程序,如果用户在提示时不输入任何内容就按回车键,将出现一条错误消息,还有一些相关问题出在什么地方的信息(栈跟踪),如下所示:
Traceback (most recent call last): ...
ValueError: invalid literal for int() with base 10: ''
这种异常未被try/except语句捕获,这理所当然,因为你没有预测到这种问题,也没有采取相应的措施。在这些情况下,与其使用并非要捕获这些异常的try/except语句将它们隐藏起来,还不如让程序马上崩溃,因为这样你就知道什么地方出了问题。然而,如果你就是要使用一段代码捕获所有的异常,只需在except语句中不指定任何异常类即可。
try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) print(x / y)
except: print('Something wrong happened ...')
现在,用户想怎么做都可以。
Enter the first number: "This" is *completely* illegal 123
Something wrong happened ...
像这样捕获所有的异常很危险,因为这不仅会隐藏你有心理准备的错误,还会隐藏你没有考虑过的错误。这还将捕获用户使用Ctrl + C终止执行的企图、调用函数sys.exit来终止执行的企图等。在大多数情况下,更好的选择是使用except Exception as e并对异常对象进行检查。这样做将让不是从Exception派生而来的为数不多的异常成为漏网之鱼,其中包括SystemExit和KeyboardInterrupt,因为它们是从BaseException(Exception的超类)派生而来的。
8.3.6 万事大吉时
在有些情况下,在没有出现异常时执行一个代码块很有用。为此,可像条件语句和循环一样,给try/except语句添加一个else子句。
try: print('A simple task')
except: print('What? Something went wrong?')
else: print('Ah ... It went as planned.')
如果你运行这些代码,输出将如下:
A simple task
Ah ... It went as planned.
通过使用else子句,可实现8.3.3节所说的循环。
while True: try: x = int(input('Enter the first number: ')) y = int(input('Enter the second number: ')) value = x / y print('x / y is', value) except: print('Invalid input. Please try again.') else: break
在这里,仅当没有引发异常时,才会跳出循环(这是由else子句中的break语句实现的)。换而言之,只要出现错误,程序就会要求用户提供新的输入。下面是这些代码的运行情况:
Enter the first number: 1
Enter the second number: 0
Invalid input. Please try again.
Enter the first number: 'foo'
Enter the second number: 'bar'
Invalid input. Please try again.
Enter the first number: baz
Invalid input. Please try again.
Enter the first number: 10
Enter the second number: 2
x / y is 5
《Python基础教程(第3版)》笔记:第8章异常相关推荐
- python基础教程第4版-Python基础教程(第3版) 笔记(四)
第二章 列表和元素 2.1 序列概述 列表和元组的主要不同在于,列表是可以修改的,而元组不可以. 创建一个由数据库中所有人员组成的列表: >>> edward = ['Edward ...
- python基础教程第三版试题-Python基础教程(第3版) 笔记(二)
1.8模块 Python提供了完成(某人的年 龄为32.9,并想将这个值向下圆整为32,因为他还没有满33岁)这种任务的函 数floor. 导入模块,可以使用特殊命令import.函数floor包含在 ...
- Python基础教程(第3版) 笔记(一)
1.1 数和表达式: 除法运算的结果为小数,即浮点数 >>>1/2 0.5 除法运算为整数,使用双斜杠 >>>1//2 0 >>>5.0//2.4 ...
- python的符号lt和gt怎么输入_lt;lt;Python基础教程gt;gt;学习笔记 | 第12章 | 图形用户界面...
Python支持的工具包非常多.但没有一个被觉得标准的工具包.用户选择的自由度大些.本章主要介绍最成熟的跨平台工具包wxPython.官方文档: ------ 丰富的平台: Tkinter实际上类似于 ...
- python基础教程电子版-Python基础教程(第2版 修订版) pdf
Python基础教程(第2版 修订版) 目录 D11章快速改造:基础知识1 1.1安装Python1 1.1.1Windows1 1.1.2Linux和UNIX3 1.1.3苹果机(Macintosh ...
- Python基础教程(第2版 修订版) pdf
Python基础教程(第2版 修订版) 目录 D11章快速改造:基础知识1 1.1安装Python1 1.1.1Windows1 1.1.2Linux和UNIX3 1.1.3苹果机(Macintosh ...
- 《python基础教程(第二版)》学习笔记 基础部分(第1章)
<python基础教程(第二版)>学习笔记 基础部分(第1章) python常用的IDE: Windows: IDLE(gui), Eclipse+PyDev; Python(comman ...
- Python基础教程(第3版)》笔记:第6章抽象
Python基础教程(第3版)>笔记:第6章抽象 **斐波那契数列:**每个数都是前两个数的和. fibs = [0,1] for i in range(8):fibs.append(fibs[ ...
- Python 基础教程(第二版)读书笔记
Python 基础教程(第二版) 第一章 在 Python 3 中可直接使用长整数,而不必添加 L 或者 l 的后缀. print在 Python 3 中是函数. 在交互式解释器中使用 if 语句,需 ...
最新文章
- java怎么求两组整数的或集,确定整数是否在具有已知值集的两个整数(包括)之间的最快方法...
- pod setup慢的解决方法
- Hadoop参数汇总
- Kotlin中的接口回调
- android录音功能的实现
- servlet下根据相对路径找资源
- cin.ignore()函数的用法
- 关于NFSv4服务共享目录里的文件UID和GID显示为nobody的解决方法
- mysql day of week_在MySQL中按day_of_week排序
- 第一章 SQL Server 2005概述文档信息
- 汇编语言INC DEC JGE JG JLE JL JNE JE 都是什么意思
- 吞食天地2完全版乱码怎么解决_PDF转Word如何转换?PDF转Word乱码怎么解决?
- android获取浏览器cookie,获取浏览器cookie
- ps--修饰人像的皮肤瑕疵的步骤
- html按钮动态效果,8款超酷而实用的CSS3按钮动画
- ubuntuv20启动界面美化_聊一聊我的win10系统美化/使用习惯
- 汽车系统安装linux,linux系统不仅是电脑上的系统 更是会车载主流系统
- c语言二级指针与二维数组
- 网站备案后 换服务器,网站备案后更换服务器
- 【充电站】_世俗智慧_哲学智慧_.
热门文章
- 局部线性嵌入 (Locally linear embedding-LLE)原理总结
- android 点赞源码,【Ctrl.js】微信给最新一条消息点赞源码
- 亮度键消失、亮度键失灵且电脑亮度为最大 | 小米 | win11 | 解决办法最最最全合集
- Keras的loss_weights和class_weight
- macOS Monterey 12.2 (21D49) 虚拟机 IOS 镜像
- XCODE性能测试方法
- 手机怎么压缩图片?分享一下压缩的好方法
- 做PPT只会用黑体和宋体?这些可商用字体瞬间提升你的PPT档次
- 七牛 java 加水印_七牛云图片加水印
- unnormal C++