系统学习Python——异常处理:raise语句
如果要显式地触发异常,可以使用raise
语句。它们的一般形式相当简单。一条raise
语句的组成包括raise
关键字,后面跟着可选的要引发的异常类或者异常类的一个实例:
raise instance #Raise instance of class
raise class #Make and raise instance of class:makes an instance
raise #Reraise the most recent exception
如前所述,从Python 2.6和Python 3.0以后异常总是类的实例。因此,这里第一种raise
形式是最常见的。我们直接提供了一个实例,该实例要么是在raise
之前创建的,要么就是raise
语句中创建的。如果我们传入一个类,则Python会对这个类调用不带参数的默认构造函数,以此来创建被引发的一个异常实例;这个格式等同于在类引用后面添加圆括号。最后的一种形式会重新引发最近触发的异常;它通常用于异常处理程序中,用来传递已经捕获的异常。
Python 3.X中不再支持raise Exc,Args
的形式,不过该形式在Python 2.X仍然可用。在Python 3.X中,需要使用我们介绍的raise
实例构造调用形式。在Python 2.X中等价的逗号形式是一种语法的历史遗留物,目的是为了兼容现在已经废除的基于字符串的异常模型,这一模型在Python 2.X已经不复存在。如果被用到的话,这一形式将会被转换成Python 3.X的调用形式。
在早期的Python版本中,有一种raise Exc
的形式也能用于命名一个类,它在各个版本中都能被转换成raise ExC()
,来调用类的无参数构造函数。除了被废除的逗号语法之外,Python 2.X的raise
语句还能同时支持字符串和类异常。但是前者在Python 2.6中被移除并在2.5中被弃用,所以在我们不会详细介绍,现在我们需要使用新的基于类的异常。
引发异常
为了更清楚地说明,让我们看一些例子。对于内置异常,如下两种形式是等价的,两者都会引发指定的异常类的一个实例,但是第一种形式是隐式地创建实例:
raise IndexError #Class(instance created)
raise IndexError() #Instance(created in statement)
我们也可以提前创建实例,因为raise
语句接受任何类型的对象引用,下面的例子像刚才一样引发了IndexError
:
exc = IndexError() #Create instance ahead of time
raise exc
excs = [IndexError,TypeError]
raise excs[o]
当引发一个异常的时候,Python把引发的实例与该异常一起发送。如果一个try
包含了一个except name as X:
形式的分句,那么raise
中的异常实例就会赋值给变量X
:
try:...
except IndexError as X: #X assigned the raised instance object ...
as
在try
处理程序中是可选的(如果省略它,该实例则不会被赋值给一个名称),但是包含as
将使得处理程序能够访问异常实例中的数据以及异常类中的方法。
这种模型对于我们用类编写的用户定义的异常也同样有效。例如,下面的代码向异常类的构造函数中传入了参数,从而使该参数可以通过异常实例的赋值在处理程序中被使用:
class MyExc(Exception): pass
...
raise MyExc('spam’) #Exception class with constructor args
...
try:...
except MyExc as X: #Instance attributes available in handler print(X.args)
不管你如何指定异常,异常总是通过实例对象来识别的,而且在程序运行的任意时刻,至多只能有一个处于激活状态的异常实例。一旦异常在程序中某处被一条except
分句捕获,它就不会再传递给另一个try
语句了,除非它被另一个raise
语句或错误再次引发。
作用域和try except变量
我们将在后面的文章中深入学习异常对象。在Python 2.X中,一个except
分句中的异常引用变量名不单单局限于分句本身,也就是说这一变量在except
对应的代码块运行结束后,仍然可用。相反,Python 3.X会将异常引用名局限在对应的except
块中——在块执行结束后该变量将不能再被使用,这和3.X中推导表达式的临时循环变量非常相似,还有前面提到的,Python 3.X不接受Python 2.X中的except
分句逗号语法:
c:\code>py-3
>>> try:
... 1 / 0
... except Exception, X:
SyntaxError:invalid syntax>>> try:
... 1 / 0
... except Exception as X: #3.X localizes las'names to except block
... print(X)
division by zero
>>> X
NameError:name'X"is not defined
然而不同于推导循环变量的是,这一变量在Python 3.X的except
块退出后就被移除了。之所以这么做的原因在于如果不这么做,这一变量将继续持有Python运行时调用栈的一个引用,这会导致垃圾回收机制被推迟同时占用了额外的内存空间。即使你在别处使用了这一异常引用名,这种移除也将被强制执行,而且是一种比推导语法还要严格的策略:
>>> X=99
>>> try:
... 1 / 0
... except Exception as X: #3.X localizes andremoves on exit!
... print(x)
division by zero
>>> X
NameError:name'X'is not defined>>> X=99
>>> {X for X in'spam'} #2.X/3.X localizes only:not removed
{'s','a','p','m'}
>>>X
99
因此,你通常应当在try
语句的except
分句中使用独特的变量名,即便它们已经局限在这一作用域中。如果你确实需要在try
语句后引用该异常实例,你只需将该实例赋值给另一个不会被自动移除的变量名即可:
>>> try:
... 1 / 0
... except Exception as X: #3.X localizes las'names to except block
... print(X)
... saveit = X
division by zero
>>> X
NameError:name'X"is not defined
>>> saveit
ZeroDivisionError('division by zero')
利用raise
传递异常
raise
语句拥有比我们目前所看到的更加丰富的性质。例如,一个不带异常名称或额外数据值的`raise命令的作用是重新引发当前异常。一般如果需要捕获和处理一个异常,又不希望异常在程序代码中死掉时,就会采用这种形式。
>>> try:
... raise IndexError('spam') # Exceptions remember arguments
... except IndexError:
... print('propagating')
... raise # Reraise most recent exception
propagating
IndexError Traceback (most recent call last)
<ipython-input-1-5ce28f2f34b4> in <module>()1 try:
----> 2 raise IndexError('spam') # Exceptions remember arguments3 except IndexError:4 print('propagating')5 raise # Reraise most recent exception
如果这样执行ra1se
时,就能重新引发异常,并将其传递给更高层的处理程序(或者顶层的默认处理程序,它会停止程序并打印标准出错消息)。
Python 3.X异常链:raise from
异常有时能作为对其他异常的响应而被触发:它既可以是有意地被触发,也可以是由于其他新的程序错误而被触发。为了在这些情况中支持完全的开放性,Python 3.X也允许raise
语句拥有一个可选的from
分句:
raise newexception from otherexception
当from
分句被使用在一个显式raise
请求中的时候,from
后面跟的表达式指定了另一个异常类或实例,该异常(即上面的otherexception
.)会附加到新引发异常(即上面的newexception
)的__cause__
属性。如果新引发的异常没有被捕获,那么Python会把两个异常都作为标准出错消息的一部分打印出来:
>>> try:
... 1 / 0
...except Exception as E:
... raise TypeError('Bad!') from E # Explicitly chained exceptions
Traceback (most recent call last):File "<stdin>",line 2,in <module>
ZeroDivisionError: division by zero The above exception was the direct cause of the following exeeption:Traceback(most recent call last):File "<stdin>",line 4,in <module>
TypeError: Bad
当在一个异常处理程序内部,由程序错误隐式地引发一个异常的时候,一个相似的过程会紧接着自动发生。前一个异常会添加到新异常的__context__
属性中,并且如果该异常未捕获的话,则同样会显示在标准出错消息中:
>>> try:
... 1 / 0
... except:
... badname # Implicitly chained exceptions
Traceback(most recent call last):
File "<stdin>",line 2,in <module>
ZeroDivisionError: division by zeroDuring handling of the above exception, another exception occurred:Traceback(most recent call last):
File "<stdin>",line 4,in <module>
NameError:name 'badname' is not defined
在上述两种情况中,因为原先异常在被添加到新异常对象的同时,自身可能也有添加的原因(更早的异常),所以异常的因果链可以为任意长度,并都会被完整地打印在错误信息中。也就是说,错误信息可以包含多于两条的异常。最终的效果是,在隐式和显式上下文中都能让程序员知道所有涉及的异常,只要一个异常触发了另一个:
>>> try:
... try:
... raise IndexError()
... except Exception as E:
... raise TypeErro() from E
... except Exception as E:
... raise SyntaxError() from E
Traceback(most recent call last):
File "<stdin>",line 3,in <module>
IndexError The above exception was the direct cause of the following exception:Traceback(most recent call last):File "<stdin>",line 5,in <module>TypeError The above exception was the direct cause of the following exception:Traceback(most recent call last):File "<stdin>",line 7,in <module>
SyntaxError:None
同理,下面的代码会显示三条异常,尽管它们都是隐式产生的:
>>> try:
... try:
... 1 / 0
... except:
... badname
... except:
open('nonesuch')
与合并try
语句一样,连锁引发的异常和其他语言中的用法相似(包括Java和C#),然而我们很难说这些语言之间到底是谁借鉴了谁。在Python中,这是一个高级的并且多少还有些难懂的扩展。事实上,Python3.3新增了种能够阻止异常连锁引发的方式:Python 3.3禁用连锁异常:raise from None
。Python 3.3引人了一种新的语法形式使用None
作为from
分句的异常名称:
raise newexception from None
这条语句能禁用前文中提到的连锁异常上下文的显示。其效果是在实际处理异常连锁的过程中,显示更少的在异常类型间转换的错误信息。
系统学习Python——异常处理:raise语句相关推荐
- 零基础如何系统学习Python?Python入门必看
零基础如何系统学习python,绝大多数零基础转行者学习编程的目的就是想找一份高薪有发展前景的工作,哪个编程语言就业前景好越值得学习.零基础的同学学Python是一个不错的选择. 零基础学习pytho ...
- 系统学习Python——模块和包:模块基础知识
分类目录:<系统学习Python>总目录 模块是最高级别的程序组织单元,它将程序代码和数据封装起来以便再利用,同时提供自包含的命名空间从而避免程序出现变量名冲突.从实际的角度来看,模块往往 ...
- Python 异常处理--raise函数用法
Python 异常处理--raise函数用法 参考文章: (1)Python 异常处理--raise函数用法 (2)https://www.cnblogs.com/darkgui34/p/405074 ...
- 初学者应该如何有效率的系统学习Python开发
首先告诉你的是,零基础学习开始系统学习Python肯定难,Python的专业程度本身就不简单,学习这事本来就是一件非常煎熬的事情,人都不愿意学习,可是没办法,为了生存掌握一个技能,你必须学,如果你认真 ...
- 系统学习Python——进度条模块tqdm
分类目录:<系统学习Python>总目录 tqdm在阿拉伯语中是"进步"的意思(塔卡杜姆,تقدّم)并且是西班牙语中"我非常爱你"的缩写.在Pyt ...
- 系统学习Python——字符串(str):字符串格式化表达-[基础知识]
分类目录:<系统学习Python>总目录 相关文章: · 字符串格式化表达:基础知识 · 字符串格式化表达:格式化表达式 · 字符串格式化表达:格式化方法 Python还提供了一种高级的方 ...
- 系统学习Python——单元测试unittest:编写测试用例
分类目录:<系统学习Python>总目录 相关文章: · 单元测试unittest:框架结构 · 单元测试unittest:测试固件 · 单元测试unittest:编写测试用例 · 单元测 ...
- 系统学习Python——单元测试unittest:测试报告
分类目录:<系统学习Python>总目录 相关文章: · 单元测试unittest:框架结构 · 单元测试unittest:测试固件 · 单元测试unittest:编写测试用例 · 单元测 ...
- 系统学习Python——单元测试unittest:命令行执行测试
分类目录:<系统学习Python>总目录 相关文章: · 单元测试unittest:框架结构 · 单元测试unittest:测试固件 · 单元测试unittest:编写测试用例 · 单元测 ...
最新文章
- JavaScript作用域链
- Python数据结构与算法(第五天)
- 【ArcGIS风暴】ArcGIS求一个矢量图层中多个图斑的“四至点”坐标案例教程
- Unity的 UNet组件介绍
- LeetCode 216. 组合总和 III(排列组合 回溯)
- matlab实验符号计算答案,实验7 Matlab符号计算.doc
- 远程计算机关闭了怎么办,怎么远程关闭电脑 远程关闭电脑方法【详细步骤】...
- mac本 安装淘宝镜像
- 如何进入Github【亲测有效】
- java获得指定时间的前几天或后几天是哪一天
- 计算机正在准备从D盘中回收,电脑一直显示正在启动怎么选择重灌系统
- linux下ping提示dup,ping出现dup问题
- 猴子选大王(c语言)
- NTC热敏电阻温度计算公式
- 如何将图片放大不失真,保持清晰度?
- android中的各种缓存目录
- uva 11419 SAM I AM (最小覆盖 König定理)
- 2009年3月30日
- 七段数码管数字字母显示
- 多维分析前端页面卡顿不流畅怎么办