Python异常处理回顾与总结
1 引言
在我们调试程序时,经常不可避免地出现意料之外的情况,导致程序不得不停止运行,然后提示大堆提示信息,大多是这种情况都是由异常引起的。异常的出现一方面是因为写代码时粗心导致的语法错误,这种错误在程序编译时就可以发现;另一方面也可能是因为程序逻辑错误,这种错误往往是不可避免地,只能通过异常处理来防止程序退出。
2 异常类型
Python自带的异常处理机制非常强大,提供了很多内置异常类,可向用户准确反馈出错信息。Python是面向对象语言,认为一切皆对象,所以异常也是对象。Python异常处理机制中的BaseException是所有内置异常的基类,但用户定义的类并不直接继承BaseException,所有的异常类都是从Exception继承,且都在exceptions模块中定义。Python自动将所有异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可使用异常。
Python内置异常类继承层次结构如下:
BaseException # 所有异常的基类
+-- SystemExit # 解释器请求退出
+-- KeyboardInterrupt # 用户中断执行(通常是输入^C)
+-- GeneratorExit # 生成器(generator)发生异常来通知退出
+-- Exception # 常规异常的基类
+-- StopIteration # 迭代器没有更多的值
+-- StopAsyncIteration # 必须通过异步迭代器对象的__anext__()方法引发以停止迭代
+-- ArithmeticError # 各种算术错误引发的内置异常的基类
| +-- FloatingPointError # 浮点计算错误
| +-- OverflowError # 数值运算结果太大无法表示
| +-- ZeroDivisionError # 除(或取模)零 (所有数据类型)
+-- AssertionError # 当assert语句失败时引发
+-- AttributeError # 属性引用或赋值失败
+-- BufferError # 无法执行与缓冲区相关的操作时引发
+-- EOFError # 当input()函数在没有读取任何数据的情况下达到文件结束条件(EOF)时引发
+-- ImportError # 导入模块/对象失败
| +-- ModuleNotFoundError # 无法找到模块或在在sys.modules中找到None
+-- LookupError # 映射或序列上使用的键或索引无效时引发的异常的基类
| +-- IndexError # 序列中没有此索引(index)
| +-- KeyError # 映射中没有这个键
+-- MemoryError # 内存溢出错误(对于Python 解释器不是致命的)
+-- NameError # 未声明/初始化对象 (没有属性)
| +-- UnboundLocalError # 访问未初始化的本地变量
+-- OSError # 操作系统错误,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合并到OSError中,构造函数可能返回子类
| +-- BlockingIOError # 操作将阻塞对象(e.g. socket)设置为非阻塞操作
| +-- ChildProcessError # 在子进程上的操作失败
| +-- ConnectionError # 与连接相关的异常的基类
| | +-- BrokenPipeError # 另一端关闭时尝试写入管道或试图在已关闭写入的套接字上写入
| | +-- ConnectionAbortedError # 连接尝试被对等方中止
| | +-- ConnectionRefusedError # 连接尝试被对等方拒绝
| | +-- ConnectionResetError # 连接由对等方重置
| +-- FileExistsError # 创建已存在的文件或目录
| +-- FileNotFoundError # 请求不存在的文件或目录
| +-- InterruptedError # 系统调用被输入信号中断
| +-- IsADirectoryError # 在目录上请求文件操作(例如 os.remove())
| +-- NotADirectoryError # 在不是目录的事物上请求目录操作(例如 os.listdir())
| +-- PermissionError # 尝试在没有足够访问权限的情况下运行操作
| +-- ProcessLookupError # 给定进程不存在
| +-- TimeoutError # 系统函数在系统级别超时
+-- ReferenceError # weakref.proxy()函数创建的弱引用试图访问已经垃圾回收了的对象
+-- RuntimeError # 在检测到不属于任何其他类别的错误时触发
| +-- NotImplementedError # 在用户定义的基类中,抽象方法要求派生类重写该方法或者正在开发的类指示仍然需要添加实际实现
| +-- RecursionError # 解释器检测到超出最大递归深度
+-- SyntaxError # Python 语法错误
| +-- IndentationError # 缩进错误
| +-- TabError # Tab和空格混用
+-- SystemError # 解释器发现内部错误
+-- TypeError # 操作或函数应用于不适当类型的对象
+-- ValueError # 操作或函数接收到具有正确类型但值不合适的参数
| +-- UnicodeError # 发生与Unicode相关的编码或解码错误
| +-- UnicodeDecodeError # Unicode解码错误
| +-- UnicodeEncodeError # Unicode编码错误
| +-- UnicodeTranslateError # Unicode转码错误
+-- Warning # 警告的基类
+-- DeprecationWarning # 有关已弃用功能的警告的基类
+-- PendingDeprecationWarning # 有关不推荐使用功能的警告的基类
+-- RuntimeWarning # 有关可疑的运行时行为的警告的基类
+-- SyntaxWarning # 关于可疑语法警告的基类
+-- UserWarning # 用户代码生成警告的基类
+-- FutureWarning # 有关已弃用功能的警告的基类
+-- ImportWarning # 关于模块导入时可能出错的警告的基类
+-- UnicodeWarning # 与Unicode相关的警告的基类
+-- BytesWarning # 与bytes和bytearray相关的警告的基类
+-- ResourceWarning # 与资源使用相关的警告的基类。被默认警告过滤器忽略。
3 异常捕获与处理
当发生异常时,我们就需要对异常进行捕获,然后进行相应的处理。使用Python异常处理机制时,把可能发生错误的语句放在try模块里,用except来处理异常,每一个try,都必须至少对应一个except。Python异常处理机制常用的几种异常捕获和处理结构如下:
第一种:try - except
try:
<语句>
except:
<异常处理>
这种结构使用简单,但可能会引发一些设计问题:尽管使用方便,但可能捕获与程序无关、意料之外的系统异常,而且可能意外拦截其他处理器的异常。例如,在Python中,即表示系统离开调用(sys.exit())也会出发异常,然而这种异常我们通常不需要捕获。所以,这种结构尽量少用。
import time
import sys
try:
while True:
a = int(input('请输入一个数字:'))
if a==0:
sys.exit()
else:
print('您输入的数字是:{}'.format(a))
time.sleep(1)
except:
print('发生异常了……')
当输入数字0时,输出如下:
请输入一个数字:0
发生异常了……
事实上,系统知识正常退出,并不算异常,但是只使用except,Python会将系统离开调用当做异常来捕获。
(2)try-except<异常名>
try:
<语句>
except <异常名> [as e]:
<异常处理>
except中,as e是可选的,意思是将捕获的异常类实例化对象赋值给e(当然也可以用其他变量名),在except下面的代码块中,我们将可以通过这个e访问异常实例化对象中的方法和数据。另外,except子句的个数理论上是不限的,不过不能将父类置于子类前面。在上文中提到,Exception类是所有Python异常类的父类,所以except Exception将可以捕获任何异常,换句话说,它是万能异常处理句式。
try:
a = int(input('请输入一个数字:'))
except ValueError as e:
print(e)
当输入一个非数字类字符时,输出如下:
请输入a的值:j
invalid literal for int() with base 10: 'j'
如果输入b的值为0,输出如下:
请输入a的值:1
请输入b的值:0
division by zero
(3)try-except (<异常类1>, <异常类2>, ...)
try:
<语句>
except (<异常类1>, <异常类2>, ...):
<异常处理>
try:
a = int(input('请输入a的值:'))
b = int(input('请输入b的值:'))
c = a/b
except (ValueError , ZeroDivisionError) as e:
print(e)
当输入一个非数字类字符时,输出如下:
请输入a的值:j
invalid literal for int() with base 10: 'j'
如果输入b的值为0,输出如下:
请输入a的值:1
请输入b的值:0
division by zero
(4)try-except-else
try:
<语句>
except <异常名>:
<异常处理>
else:
<语句> # try语句中没有异常则执行此段代码
如果说except是在try中代码抛出异常时执行,那么else语句下面的代码将在try顺利执行(没有抛出任何异常)的情况下才会执行。
try:
a = int(input('请输入a的值:'))
b = int(input('请输入b的值:'))
c = a/b
except (ValueError , ZeroDivisionError) as e:
print(e)
else:
print('a/b的结果为:{}'.format(c))
当输入a和b的值都为数字时,才会执行else部分代码,输出结果如下:
请输入a的值:4
请输入b的值:2
a/b的结果为:2.0
(5)try-except-finally
try:
<语句>
except <异常类>:
<异常处理>
finally:
<语句> # 不管try中代码是否抛出异常,都会执行此段代码
finally中的代码无论try中代码是否抛出异常都会执行。
try:
a = int(input('请输入a的值:'))
b = int(input('请输入b的值:'))
c = a/b
except (ValueError , ZeroDivisionError) as e:
print(e)
else:
print('a/b的结果为:{}'.format(c))
finally:
print('无论你输入什么值,finally都会执行……')
4 主动抛出异常(raise)
有时候,异常可以作为代码运行的标志,通过主动触发异常可以改变代码的运行路线,从而提高代码健壮性。主动触发异常需使用raise关键字,其语法结构如下:
raise [Exception [, args [, traceback]]]
def fun(x , y):
try:
print('fun()方法开始执行……')
if isinstance(x,int) and isinstance(y,int):
return x+y
else:
raise TypeError('类型错误')
except Exception as e:
print(e)
finally:
print('fun()方法执行结束……')
fun(2 , '')
输出结果:
fun()方法开始执行……
类型错误
fun()方法执行结束……
5 断言(assert)
assert语句根据后面的表达式的真假来控制程序流。 asset语法结构如下:
assert expression,'information'
若为expression结果为True,则往下执行。若为False,则中断程序并调用默认的异常处理器抛出AssertionError异常,同时输出指定的提示信息。
def fun(x):
print('fun()方法开始执行……')
assert x<0 , '抛出异常,x小于0'
print('fun()方法执行结束……')
try:
fun(2)
except Exception as e:
print(e)
输出结果:
fun()方法开始执行……
抛出异常,x小于0
可以发现,打印输出第一行语句之后,由于断言失败,抛出异常,程序直接退出。
6 with/as上下文管理器
with/as语句通常是作为try/finally语句的替代方案,不过with/as更加优雅。在有一些任务中,可能事先需要设置,然后不管在任务过程中是否顺利(有无异常抛出),最后后做清理工作。对于这种场景, with/as语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读写数据,但不管读写数据是否有异常发生,最后都要关闭文件句柄。
with/as语句的基本格式如下:
with expression [as variable] :
with-block
在这里的expression会返回一个对象,as子句是可选的,当存在as子句时,expression返回的对象会赋值给variable。
使用with/as语句将一段字符串写入文件:
with open('data.txt' , 'w') as myfile:
myfile.write('')
不适用with/as语句,如果要实现同样的效果,只能这么写:
try:
myfile = open('data.txt' , 'w')
myfile.write('')
except Exception as e:
print(e)
finally:
myfile.close()
7 自定义异常类
如果Python提供的内置异常内不满足使用要求,那么,可以自定义一个异常类。自定义异常类必须继承Exception类,并且在使用时,必须通过raise关键字自动触发。
class MyError(Exception):
def __init__(self, info):
self.info = info
def __str__(self):
return '{}:{}'.format(self.__class__ .__name__, self.info)
try:
raise MyError('自定义的异常……')
except MyError as e :
print(e)
输出结果:
MyError:自定义的异常……
8 总结
本文是对Python异常处理机制的总结,较为全面的介绍了Python异常处理的常用内置类,即几种异常捕获/处理句式结构,主动触发异常,断言,with上下文管理协议,自定义异常类等内容。
Python异常处理回顾与总结的更多相关文章
- python异常处理(基础)
之前在学习python的时候有整理过python异常处理的文章,不够简单也不够完整,所以决定再整理一篇,算做补充. http://www.cnblogs.com/fnng/archive/2013/0 ...
- Python异常处理 分类: python Raspberry Pi 服务器搭建 2015-04-01 13:22 172人阅读 评论(0) 收藏
一个程序要保持稳定运行必须要有异常处理,本文将简单介绍Python中的try-except..异常处理语句的使用. 该种异常处理语法的规则是: 执行try下的语句,如果引发异常,则执行过程会跳到第一个 ...
- Python 异常处理--raise函数用法
raise语句手工引发一个异常: "raise" [expression ["," expression ["," expression]] ...
- [Python学习笔记][第八章Python异常处理结构与程序调试]
1/30 第八章Python异常处理结构与程序调试 异常处理 try-except结构 try: try块 except Exception: except块 try-except-else结构 tr ...
- python异常处理try,except,else,finally,raise
先看下else的使用: try: ... exception: ... else: ... 只有在try中没有发生任何异常,所有代码完全成功的情况下才会转入else 再看下finally: final ...
- Python 异常处理
Python 异常处理 python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误.你可以使用该功能来调试python程序. 异常处理: 本站Python教程会具体介绍. 断言 ...
- python异常处理的哲学
所谓异常指的是程序的执行出现了非预期行为,就好比现实中的做一件事过程中总会出现一些意外的事.异常的处理是跨越编程语言的,和具体的编程细节相比,程序执行异常的处理更像是哲学.限于认知能力和经验所限,不可 ...
- Python异常处理总结
一.何谓异常处理 在我们调试程序时,经常不可避免地出现意料之外的情况,导致程序不得不停止运行,然后提示大堆提示信息,大多是这种情况都是由异常引起的.异常的出现一方面是因为写代码时粗心导致的语法错误,这 ...
- python异常处理与断言以及日志模块
python异常处理与断言 目录: 1.异常处理 2.断言(assert) 3.日志模块(logging) 4.修改之前的车票信息查询,把日志模块.异常处理加进去 1.异常处理 代码如下: 语法: t ...
随机推荐
- Java: 扩大字节缓存区的大小,提升AIO的处理性能(并发性能)
前些日了,对AIO与NIO的并发性能进行了比较,在低并发的情况下,NIO性能表现比AIO好一些,主要原因是,NIO中可以使用FileChannel.transferTo(long position, ...
- 1.Unix,Linux起源与编译原理
一.UNIX操作系统 作者:丹尼斯.里奇,肯.汤普逊 版权:贝尔实验室 时间:1971 特点:多用户,多任务(多进程),多CPU(多种CPU架构),高安全,高可靠,高性能,高稳定 应用:构 ...
- Jenkins-Pipeline 流水线发布
基于docker部署 1.部署jenkins $ yum -y install java $ java -version openjdk version "1.8.0_181" O ...
- 网络报错:“The connection is not for this device.”
网络报错:“The connection is not for this device.” 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 记得在前几天工作的时候,有一个同时通过微信 ...
- node.js通过edge访问.net动态链接库
从了解node.js到现在经历了几个月时间,一直忙于实际的项目,没有动手写点关于node.js的代码.最近将开发工作安排就绪,个人的时间相对从容了,所以这几天开始测试一下node.js. 多年来,一直 ...
- 一个很实用的css3兼容工具很多属性可以兼容到IE6
当你看到这样的效果图是不是已经崩溃了 css3没出来之前大部分人基本都是用图片的方式拼出来的 腾讯邮箱就是这么做的 然后你想和设计说换直角吧.我用图片的好烦的感觉!而且我们还要兼容到ie6 她和你说别 ...
- javascript实现的拖拽回放
这个功能很简单,直接贴代码啊: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...
- 五个案例让你明白GCD死锁(转)
转自:http://ios.jobbole.com/82622/ 死锁一直都是在使用多线程时,需要注意的一个问题.以前对同步.异步,串行.并行只有一个模糊的概念,想想也是时候整理一下了.再看看之前的博 ...
- HTML5 CSS Reset
最近在学习HTML和CSS,发现一个不错的模板,放于此处. /* html5doctor.com Reset Stylesheet v1.6.1 Last Updated: 2010-09-17 Au ...
- 【干货】操纵时间 感受威胁 MAC time时间戳视角
来源:Unit 4: Unix/Linux Forensics Analysis 4.1 Unix/Linux Forensics Analysis MAC Times Sleuthkit工具的MAC ...