Python异常信息的捕获和处理

什么是异常

异常是一种影响程序运行的事件。当发生超出程序规则之外的事情时,程序就会“一脸懵逼”而卡在那里,严重的程序甚至直接选择奔溃。


异常的抛出机制:

  1. 如果在运行时发生异常,解释器会查找相应的处理语句(称为handler).
  2. 要是在当前函数里没有找到的话,它会将异常传递给上层的调用函数,看看那里能不能处理。
  3. 如果在最外层(全局“main”)还是没有找到的话,解释器就会退出,同时打印出traceback以便让用户找到错误产生的原因。


异常的类型

下表转载于http://www.runoob.com/python/python-exceptions.html

异常名称 描述
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告


异常的捕获和处理

异常就像跑得飞起的兔子,在兔子屁股后面狂追一通只会劳心劳力。正确的方法是使用陷阱去捕获“兔子”,而常用的捕获异常的陷阱分两类:

try 捕获有Python或程序本身引发的异常

raise 手工引发一个异常


try...except...else

try:
    statement1
except <name>:  # 异常名字name
    statement2
except <name>,<value>:  # 获取异常的附加数据
    statement3
else:
    statement  # 如果无异常则执行该部分语句
这个过程的原理很简单,打个比方:

try就好比你往外撒了一个渔网,如果有“鱼”(异常),就进入到except,这部分就好比根据鱼的种类做不同的动作,如果没有鱼,就执行else部分。

下面是往一个没有写入权限的文件写数据的例子,此时会发生文件流错误IOError。

try:
    file = open('testfile', 'w')
    file.write('一个测试异常的文件')
except IOError:
    print('Error: 未找到文件或文件不存在')
else:
    print('写入操作成功')
    file.close()
执行以上代码,结果如下:

Error: 未找到文件或文件不存在


使用except不带异常类型

如果你不知道程序运行过程肯能会发生什么异常的名字,可以直接以except捕获所有可能的异常。当然这个方式就无法识别出具体的异常信息。

try:
    statement1
except:
    statement2
else:
    statement3

try...finally

try-finally语句是无论是否发生异常,都将执行finally部分的代码,通常用于文件的关闭等动作。可以配合except、else使用。

try:
    statement1
except:
    statement2
else:
    statement3
finally:
    statement4

继续以上述文件写入的操作为例

try:
    file = open("testfile", "w")
    try:
        file.write("这是一个测试异常的文件")
    finally:
        print("关闭文件")
        file.close()
except IOError:
    print("Error: 未找到文件或读取文件失败")

当在try块中抛出一个异常,立即执行finally块代码。

finally块中的所有语句执行后,异常被再次触发,并执行except块代码。


异常的参数

上面讲到try...except...else时,except除了异常类型name,还有异常参数value。通常包含错误字符串,错误数据,错误位置等信息。

try:
    statement1
except ExceptionType as e:
    return e.argument

触发异常

使用raise语句触发异常

raise [Exception [, args [, traceback]]]
语句中Exception是异常的类型(例如,NameError)参数是一个异常参数值。该参数是可选的,如果不提供,异常的参数是"None"。

最后一个参数是可选的(在实践中很少使用),如果存在,是跟踪异常对象。

def mtest(str):
	if str == 'Hello':
		raise NameError('无效输入')
	if str.isdigit():
		raise TypeError('数据类型错误')
try:
	#mtest('1')
	mtest('Hello')
except NameError as e:
	print(e)
except TypeError as e:
	print(e)
else:
	print('Done')

为了捕获多个异常,除了上面所示的声明多个except语句外,还可以在一个except语句后将多个异常列成一个元组,例如:

except (zeroDivisionError, TypeError)


自定义异常类型

下面是从Exception类派生的一个自定义异常类,重写了默认的__init__()异常。

class MyError(Exception):
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return repr(self.value)

try:
	raise MyError(2*2)
except MyError as e:
	print('Exception occured, value:', e.value)

断言assert

assert False,'error...'
print 'continue'
这个语句,先判断assert后面紧跟的语句是True还是False。如果是True则执行print,如果是False则中断程序,调用默认的异常处理器,同时输出assert语句逗号后面的提示信息。上述例子程序会中断,提示error,后面的print不执行。


with...as

我们平时在使用类似文件的流对象时,使用完毕后要调用close方法关闭,很麻烦。

这里with…as语句提供了一个非常方便的替代方法:open打开文件后将返回的文件流对象赋值给f,然后在with语句块中使用。with语句块完毕之后,会隐藏地自动关闭文件。

如果with语句或语句块中发生异常,会调用默认的异常处理器处理,但文件还是会正常关闭。

with open('test.txt', 'r') as f:
    f.read()
    print(2/0)
print('continue')


其他说明

  1. 在2.x时代,所有类型的对象都是可以被直接抛出的,在3.x时代,只有继承自BaseException的对象才可以被抛出。
  2. 2.x raise语句使用逗号将抛出对象类型和参数分开,3.x取消了这种奇葩的写法,直接调用构造函数抛出对象即可。
  3. 在2.x时代,异常在代码中除了表示程序错误,还经常做一些普通控制结构应该做的事情,在3.x中可以看出,设计者让异常变的更加专一,只有在错误发生的情况才能去用异常捕获语句来处理。
  4. 捕获一个通用异常时,在ExceptionBaseException之间,建议使用Exception。虽然BaseException包含了Exception,但是Exception所包含的范围就足够了。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值