Python笔记----异常处理
异常处理
Python的异常机制主要依赖:try,except,else,finally,raise五个关键字。
- try块放置的是可能引发异常的代码;
- except后对应的是异常类型和一个代码块,用于表明该except块处理这种类型的代码;
- 在多个except块之后可以放一个else块,表明程序不出现异常时还要执行else块;
- finally块用于回收在try块中打开的物理资源,异常机制保障finally块总被执行;
- raise用于引发一个实际的异常。raise可单独作为语句使用,引发一个具体的异常对象。
异常概述
使用异常处理机制的Python程序有更好的容错性,更加健壮。
异常处理机制
1.使用try…except捕获异常
以下是Python异常处理机制的语法结构:
如果在执行 try 块里的业务逻辑代码时出现异常,系统自动生成一个异常对象,该异常对象被提交给Python 解释器,这个过程被称为引发异常。
当Python解释器收到异常对象时,会寻找能处理该异常对象的 except 块,如果找到合适的except 块,则把该异常对象交给该 except 块处理,这个过程被称为捕获异常。
如果 Python 解释器找不到捕获异常的 except 块,则运行时环境终止, Python 解释器也将退出。
不管程序代码块是否处于try块中,甚至包括 except 块中的代码,只要执行该代码块时出现了异常,系统总会自动生成一个 Error 对象。例如:
2.异常类的继承体系
当程序发生不同的意外情况时,系统会生成不同的异常对象, Python 解释器就 会根据该异常对象所属的异常类来决定使用哪个 except块处理该异常。
Python的所有异常类都从 BaseException 生而来,提供 丰富的异常类。
Python 的所有异常类的基类是 BaseException ,但如果用户要实现自定义异常,则不应该继承这个基类,而是应该继承 Exception 类。
import sys
try:
a = int(input())
b = int(input())
c= a / b
print('输入的两个数相除的结果为: ', c)
except IndexError:
print('索引错误,运行程序时输入的参数个数不够')
except ValueError:
print('数值错误,程序只能接收整数参数')
except ArithmeticError:
print('算术错误,比如分母不应为0')
except Exception:
print('未知异常')
运行结果如下:
3.多异常捕获
Python 的一个except 块可以捕获多种类型的异常。
将多个异常类用圆括号括起来,中间用逗号隔开,其实就是构建多个异常类的元组。
import sys
try:
a = int(input())
b = int(input())
c= a / b
print('输入的两个数相除的结果为: ', c)
except (IndexError, ValueError, ArithmeticError):
print('索引错误,数值错误,算术错误之一')
except:
print('未知异常')
最后一行代码只有 except 关键字,并未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个except块。
4.访问异常信息
如果程序需要在 except 块中访问异常对象的相关信息,则可通过为异常对象声明变量来实现。当Python 解释器决定调用某个 except 块来处理该异常对象时,会将异常对象赋值给 except 块后的 异常变量,程序即可通过该变量来获得异常对象的相关信息。
所有的异常对象都包含了如下几个常用属性和方法:
- args :该属性返回异常的错误编号和描述字符串。
- errno :该属性返回异常的错误编号。
- stre or :该属性返回异常的描述宇符串。
- with_traceback(): 通过该方法可处理异常的传播轨迹信息。
'''
演示如何访问异常信息
'''
def foo():
try:
fis = open('aaa.txt')
except Exception as e:
#访问异常的错误编号和详细信息
print(e.args)
#访问异常的错误编号
print(e.errno)
#访问异常的详细信息
print(e.strerror)
foo()
运行结果如下:
如果要访问异常对象,只要在单个异常类或异常类元组(多异常捕获) 之后使用 as 再加上异常变量即可。
5.else块
Python 的异常处理流程中还可添加else块,当 try 块没有出现异常时,程序会执行else块。
s = input('请输入除数')
try:
result = 20 / int(s)
print('20除以%s的结果是: %g' % (s, result))
except ValueError:
print('值错误, 你必须输入数值')
except ArithmeticError:
print('0不可以做除数')
else:
print('无异常')
运行结果如下:
当 try 块没有异常,而else块有异常时,就能体现出else 块的作用了。
def else_test():
s = input('请输入除数')
result = 20 / int(s)
print('20除以%s的结果是: %g' % (s, result))
def right_main():
try:
print('try块无异常')
except:
print('程序出现异常')
else:
# 将else_test放在else中
else_test()
def wrong_main():
try:
print('try块的代码无异常')
# 将else_test放在try的代码的后面
else_test()
except:
print('程序出现异常')
wrong_main()
right_main()
运行结果如下:
对比上面两个输出结果,不难发现,放在 else 块中的代码所引发的异常不会被except 块捕获。 如果希望某段代码的异常能被后面 except 块捕获,那么就应该将这段代码放在 try 块的代码之后。 如果希望某段代码的异常能向外传播(不被 except 块捕获〉,那么就应该将这段代码放在 else 块中。该异常将会传播给 python 解释器, 导致程序中止 。
6.使用finally回收资源
有些时候,程序在 try块里打开了一些物理资源(例如数据库连接、网络连接和磁盘文件等〉, 这些物理资源都必须被显式回收。
Python的垃圾回收机制不会回收任何物理资源,只能回收堆内存中对象所占用的内存。
Python完整的异常处理语法结构如下:
import os
def test():
fis = None
try:
fis = open('a.txt')
except OSError as e:
print(e.strerror)
# return语句强制方法返回
# 执行到该语句,程序立即结束该方法
# 但会执行finally块中的代码
return
# 若将return注释,执行os.exit()方法,则不会执行finally块中的内容
# os.exit()
finally:
# 关闭磁盘文件,回收资源
if fis is not None:
try:
# 关闭资源
fis.close()
except OSError as ioe:
print(ioe.strerror)
print('执行finally块里的资源回收')
test()
不要在 finally 块中使用如 return,raise等导致方法中止的语句,一旦在 finally 块中使用了 return或raise 语句,将会导致 try 块、 except 块中的 return或raise 语句失效。
这是因为,如果 Python 程序在执行try块、 except 块时遇到了 return或raise 语句,这两条语句都会导致该方法立即结束,那么系统执行这两条语句并不会结束该方法,而是去找该异常处理流程中的 finally 块,如果没有找到 finally 块,程序立即执行 return或rais巳语句,方法中止;如果找到 finally 块,系统立即开始执行 finally 。只有当 finally 块执行完成后,系统才会再次跳回来执行 try 块、 except 块里的 return或raise语句:如果在finallt块里也使用了 return或raise 等导致方法中止的语句, finally 块己经中止了方法,系统将不会跳回去执行try块、 except 块里的任何代码。
7.异常处理的嵌套
在 finally 块中也包含了一个完整的异常处理流程,这种在 try 块、 except 块或 finally 块中包含完整的异常处理流程的情形被称为异常处理嵌套。
通常没有必要使用超过两层的嵌套异常处理,使用层次太深的嵌套异常处理没有太大必要,而且容易导致程序的可读性降低。