了解python之异常处理
目录
概念
- try工作原理
- 捕获异常的语法
抛出异常
python捕获多个异常
捕捉对象
异常中的else
自定义异常
try中的finally子句
概念:
程序运行过程中出现的报错,我们称之为错误,也可以称为异常,或者说程序没有按照预期运行。错误都是异常,但异常并不一定都是错误。
python运行的程序报错,常见有NameError、SyntaxError、TypeError、ValueError等,这些都称为异常。异常是一个事件,该事件会在程序执行过程中发生,影响程序的正常执行。
一般情况下,在python无法正常处理程序时就会发生异常,异常是python的一个对象,表示一个错误。当python脚本发生异常时,我们需要捕获并管理异常,否则程序会终止。
例1:
print(a)
##输出结果:
NameError: name 'a' is not defined
try的工作原理:
开始一个try语句后,python就在当前的程序上下文中做标记,当出现异常时,就可以回到做标记的地方,首先需要执行try子句,接下来发生什么依赖于执行时是否出现异常。如果try后的语句执行时发生异常,程序就跳回try并执行except子句。异常处理完毕,控制流就可以通过整个try语句了(除了在处理异常时又引发了新的异常)
捕获异常的语法:
try:
<语句>
except<名字>:
语句 #如果try部分引发了异常,执行这个语句
例2:
def exp_exception(x,y):
try:
a=x/y
print('a=',a)
return a
except Exception:
print('程序出现异常,异常信息是:被除数是0')
exp_exception(2,0)
##输出结果
程序出现异常,异常信息是:被除数是0
抛出异常
python可以使用raise语句抛出一个指定的异常,也可以使用类(Exception的子类)或者实例参数调用raise语句引发异常。使用类的时候程序会自动创建实例。
例3:
raise Exception
##输出结果:
raise Exception
Exception
//
raise NameError('this is NameError')
##输出结果:
raise NameError('this is NameError')
NameError: this is NameError
例4:
try:
raise NameError('This is NameError')
except NameError:
print('An exception happened..')
#不带raise语句
##输出结果:
An exception happened..
///
try:
raise NameError('This is NameError')
except NameError:
print('An exception happened..')
raise
##输出结果:
raise NameError('This is NameError')
NameError: This is NameError
An exception happened..
使用raise可以输出更深层次的异常,在使用过程中,可以借助这个方法得到更详细的信息。
我们之前说的异常:NameError、SyntaxError、TypeError、ValueError等异常类称为内建异常类。在python中,内建的异常类有很多,可以使用dir函数罗列出异常类的内容,并用在raise语句中,如raise NameError这种,下面列举出一些常见的异常类:
异常名称 描述
Exception 常见错误的基类
AttributeError 对象没有这个属性
IOError 输入/输出操作失败
IndexError 序列中没有此索引
KeyError 映射中没有对应的键
NameError 没有这个属性
SyntaxError 语法错误
SystemError 一般解释器系统错误
ValueError 传入无效的参数
python捕获多个异常
python怎么捕获多个异常,python支持在一个try ... except语句处理多个异常,语法如下:
try:
<语句> #运行的代码
except<name1>:
<语句> #如果在try部分触发了name1异常,就会执行这个语句
except<name2>:
<语句> #如果在try部分引发了name2异常,执行这个语句
一个try可以包含多个except子句,但子句中只有一个分支会被处理,而且是按照顺序处理的。
例5:
def mult_exception(x,y):
try:
a=x/y
b=name
except ZeroDivisionError:
print('This is ZeroDivisionError')
except NameError:
print('This is NameError')
mult_exception(2,0)
##输出结果:
This is ZeroDivisionErro
///
def mult_exception(x,y):
try:
b=name
a=x/y
except ZeroDivisionError:
print('This is ZeroDivisionError')
except NameError:
print('This is NameError')
mult_exception(2,0)
##输出结果:
This is NameError
/
def mult_exception(x,y):
try:
a=x/y
b=name
except (ZeroDivisionError,NameError,TypeError):
print('This is ZeroDivisionError or NameErr or TypeError ')
mult_exception(2,0)
##输出结果:
This is ZeroDivisionError or NameErr or TypeError
捕捉对象:
如果希望在except子句中访问异常对象的本身,也就是看到一个异常对象真正的异常信息,而不是输出自己定义的异常信息,可以使用as e的形式,我们称之为捕捉对象,如:
例6:
def model_exception(x,y):
try:
b=name
a=x/y
except (ZeroDivisionError,NameError,TypeError) as e:
print(e)
model_exception(2,0)
##输出结果:
name 'name' is not defined
//
def model_exception(x,y):
try:
a=x/y
b=name
except (ZeroDivisionError,NameError,TypeError) as e:
print(e)
model_exception(2,0)
##输出结果:
division by zero
可以看到:执行的过程中抛出异常被截获并正常输出了相关的异常信息,并且使用这个方式可以捕捉多个异常。
全捕捉:可以捕捉到所有异常
例7:
def model_exception(x,y):
try:
a=x/y
b=name
except (ZeroDivisionError,NameError,TypeError) as e:
print(e)
model_exception(2,'')
##输出结果:
unsupported operand type(s) for /: 'int' and 'str'
可以看到try/except这块的异常被隐藏了,并没有被捕捉到,如果想要处理这种异常,怎么办?
def model_exception(x,y):
try:
a=x/y
b=name
except:
print('Error happened')
model_exception(2,'')
##输出结果:
Error happened
异常中的else
如果程序执行完异常还需要做其他事情,怎么办?可以使用try ...except...else语句实现这个功能,语法:
try:
<语句> #运行的代码
except<名字>:
<语句> #在try部分如果引发了异常,执行这个位置的语句
except<名字2>,<数据>:
<语句> #如果在try部分引发了第二个异常,则获得附加数据
else:
<语句> #如果没有发生异常执行这个语句
例8:
def model_exception(x,y):
try:
a=x/y
except:
print('Error happened')
else:
print('It went as excepted')
model_exception(2,1)
##输出结果:
It went as excepted
自定义异常:异常类继承来自Exception类,可以直接继承,也可以间接继承。
例9:
class MyError(Exception):
def __init__(self):
pass
def __str__(self):
return 'This is self define error'
def my_error_test():
try:
raise MyError()
except MyError as e:
print('exception info:',e)
my_error_test()
##输出结果:
exception info: This is self define error
可以看到,程序正确的执行了自定义的异常,并且需要继承Exception类。上面只是一个简单的例子,还有很多细节需要去研究。
try中的finally子句
python中的finally子句需要和try子句一起使用,组成try/finally语句形式,try/finally语句无论发生异常与否,都会执行最后finally的代码。
例10:
def use_finally(x,y):
try:
a=x/y
finally:
print('No matter what happened,I will show in front of you')
use_finally(2,0)
##输出结果:
No matter what happened,I will show in front of you
ZeroDivisionError: division by zero
try..except..else..finally组合使用,else必须在except之后,finally在except和else之后。上面的例子可以改成如下:
def use_finally(x,y):
try:
a=x/y
except ZeroDivisionError:
print('division is zero')
finally:
print('No matter what happened,I will show in front of you')
use_finally(2,0)
##输出结果:
division is zero
No matter what happened,I will show in front of you
深入拓展学习:
Python异常处理详解
Python with/as和contextlib上下文管理使用说明