python异常处理机制
异常处理是python的一种高级工具,当异常发生时,程序会停止当前的所有工作,跳转到异常处理部分去执行。异常既可以是程序错误引发的,也可以由代码主动触发。
异常处理基本结构
try:
可能引发异常的代码
except 异常类型名称:
异常处理代码
else:
没有发生异常时执行的代码
异常报错:
try:
class test:
def getdata(self):
return self.data
y = test()
y.getdata()
except AttributeError:
print('出错了:访问对象属性出错')
else:
print('程序中没有发生错误')
print('程序执行完毕!')
结果:
出错了:访问对象属性出错!
程序执行完毕
测试else部分执行
try:
class test:
def getdata(self):
return self.data
y = test()
y.data=100
y.getdata()
except AttributeError:
print('出错了:访问对象属性出错')
else:
print('程序中没有发生错误')
print('程序执行完毕!')
结果:
程序中没有发生错误
程序执行完毕!
捕捉多个异常
在异常处理结构中,可以使用多个except语句,以捕捉可能出现的多种异常
x=[1,2]
try:
x[0]/0
except ZeroDivisionError:
print('除0错误')
except IndexError:
print('索引下标超出范围')
else:
print('没有错误')
结果:
除0错误
引发不同异常
x=[1,2]
try:
x[2]/2
except ZeroDivisionError:
print('除0错误')
except IndexError:
print('索引下标超出范围')
else:
print('没有错误')
结果
索引下标超出范围
except…as与统一处理
x=[1,2]
try:
x[0]/0
except (ZeroDivisionError,IndexError) as exp:
print('出错了:')
print('异常类型:',exp.__class__.__name__)
print('异常信息:',exp)
else:
print('没有错误')
结果
出错了:
异常类型:ZeroDivisionError
异常信息:division by zero
执行另一个异常
x=[1,2]
try:
x[2]/2
except (ZeroDivisionError,IndexError) as exp:
print('出错了:')
print('异常类型:',exp.__class__.__name__)
print('异常信息:',exp)
else:
print('没有错误')
结果:
出错了:
异常类型:IndexError
异常信息:list index out of range
捕捉所有异常
在捕捉异常时,如果except语句中没有指明异常类型,则不管发生任何类型的异常,均会执行except语句块中的异常处理,采用这种方式好处是可以捕捉所有类型的异常,还可以进一步使用sys.exc_info()方法来获得详细的异常信息
sys.exc_info()方法返回一个三元组(type,value,traceobj),type为异常类的类型,用type.__name__属性可获得异常类名称。value为异常类的实例对象,直接打印可获得异常描述信息。traceobj是一个堆栈跟踪对象(traceback对象),使用traceback模块的print_tb()方法可获得堆栈跟踪信息
x=[1,2,3]
try:
print(x[3])
except:
import sys
x=sys.exc_info()
print('异常类型:%s'%x[0].__name__)
print('异常描述:%s'%x[1])
print('堆栈跟踪信息:')
import traceback
traceback.print_tb(x[2])
结果
异常类型:IndexError
异常描述:list index out of range
堆栈跟踪信息:
File "<pyshell#200>", line 2, in <module>
异常处理结果的嵌套
python允许在异常处理结果的内部嵌套另一个异常处理结果,在发生异常时,内部没有捕捉处理的异常可以被外层捕捉
x=[1,2]
try:
try:
5/0
except ZeroDivisionError:
print('内部除0异常')
x[2]/2
except IndexError:
print('外层下标越界异常')
结果
内部除0异常
外层下标越界异常
try…finally终止行为
异常处理结构中,可以使用finally定义终止行为,不管try语句块中是否发生异常,finally语句模块中的代码都会执行
def dosome():
try:
print(5/0)
except:
print('出错了')
finally:
print('finally部分已执行')
print('over')
dosome()
结果
出错了
finally部分已执行
over
主动引发异常
python允许在代码中使用raise或assert语句主动引发异常
raise语句
raise 异常类名 #创建异常类的实例对象,并引发异常
raise 异常类实例对象 #引发异常类实例对象对应的异常
raise #重新引发刚刚的异常
用类名引发异常
>>>raise IndexError
Traceback (most recent call last):
File "<pyshell#201>", line 1, in <module>
raise IndexError
IndexError
用异常类实例对象引发异常
>>>x=IndexError()
>>>raise x
Traceback (most recent call last):
File "<pyshell#203>", line 1, in <module>
raise x
IndexError
传递异常
try:
raise IndexError
except:
print('出错了')
raise
结果:
出错了
Traceback (most recent call last):
File "<pyshell#205>", line 2, in <module>
raise IndexError
IndexError
指定异常信息
>>>raise IndexError('索引下标超出范围')
Traceback (most recent call last):
File "<pyshell#206>", line 1, in <module>
raise IndexError('索引下标超出范围')
IndexError: 索引下标超出范围
异常链:异常引发异常
可以使用raise…from…语句,使用异常来引发另一个异常
>>>try:
5/0
except Exception as x:
raise IndexError('下标越界') from x
结果
Traceback (most recent call last):
File "<pyshell#208>", line 2, in <module>
5/0
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<pyshell#208>", line 4, in <module>
raise IndexError('下标越界') from x
IndexError: 下标越界
assert语句
assert 测试表达式,data
>>>x=0
>>>assert x!=0,'变量x的值不能为0'
Traceback (most recent call last):
File "<pyshell#210>", line 1, in <module>
assert x!=0,'变量x的值不能为0'
AssertionError: 变量x的值不能为0
使用try来捕捉assert语句引发的AssertionError异常
try:
import math
x=-5
assert x>=0,'参数x必须是非负数'
except Exception as ex:
print('异常类型:',ex.__class__.__name__)
print('异常信息:',ex)
结果
异常类型: AssertionError
异常信息: 参数x必须是非负数
自定义异常类
异常类超类
异常类的共同超类:BaseException和Exception
BaseException类
BaseException类是所有异常类的顶级超类,不能直接继承BaseException类来定义自己的异常类。BaseException唯一自雷是Exception类。BaseException类为子类提供了默认的打印和状态保持行为。在创建异常类实例对象时,可以用一个字符串作为异常描述信息。在打印异常类实例对象时,显示异常描述信息
实际上,在创建异常类实例对象时,可以提供多个参数,如果子类没有覆盖继承自己BaseException类的构造方法,所有的参数均会以元组的形式保存在args属性中
>>>x=IndexError(50,'下标越界')
>>>print(x)
(50,'下标越界')
>>>x.args
(50,'下标越界')
Exception类
Exception类是其他所有python内置异常类的超类,除了GeneratorExit、KeyboardInterrupt和SystemExit,通常用户自定义类均使用Exception类作为超类
try:
5/0
except Exception as ex:
print('异常类型:',ex.__class__.__name__)
print('异常信息:',ex)
print('堆栈跟踪信息:')
import traceback
traceback.print_tb(ex.__traceback__)
结果
异常类型: ZeroDivisionError
异常信息: division by zero
堆栈跟踪信息:
File "<pyshell#214>", line 2, in <module>
创建自定义异常类
>>>class test(Exception):pass
>>>raise test('测试自定义异常类')
Traceback (most recent call last):
File "<pyshell#220>", line 1, in <module>
raise test('测试自定义异常类')
test: 测试自定义异常类
>>>
用自定义异常类保存异常日志
class myException(Exception):
logfile='app_log_file.txt'
def dolog(self):
log = open(self.logfile,'a')
from datetime import datetime
x=datetime.today()
print('\n出错了:',file=log)
print('日期时间:',x,file=log)
print('异常信息:',self.args[0],file=log)
print('堆栈跟踪信息:',file=log)
import traceback
traceback.print_tb(self.args[1],file=log)
log.close()
try:
try:
#raise myExceotion(''自定义异常类)
print(5/0)
except Exception as ex:
raise myException(ex.args[0],ex.__traceback__)
except myException as ex:
ex.dolog()
finally:
print('程序执行结束')
结果
程序执行结束
打开生成的文件内容显示:
出错了:
日期时间: 2020-03-03 16:46:09.709766
异常信息: division by zero
堆栈跟踪信息:
File "F:/PycharmProjects/untitled/biji/2020.3.3.py", line 17, in <module>
print(5/0)
***************************************************************************************************************************
Python标准异常总结
异常名 | 作用 |
---|---|
AssertionError | 断言语句(assert)失败 |
AttributeError | 尝试访问未知的对象属性 |
EOFError | 用户输入文件末尾标志EOF(Ctrl+d) |
FloatingPointError | 浮点计算错误 |
GeneratorExit | generator.close()方法被调用的时候 |
ImportError | 导入模块失败的时候 |
IndexError | 索引超出序列的范围 |
KeyError | 字典中查找一个不存在的关键字 |
KeyboardInterrupt | 用户输入中断键(Ctrl+c) |
MemoryError | 内存溢出(可通过删除对象释放内存) |
NameError | 尝试访问一个不存在的变量 |
NotImplementedError | 尚未实现的方法 |
OSError | 操作系统产生的异常(例如打开一个不存在的文件) |
OverflowError | 数值运算超出最大限制 |
ReferenceError | 弱引用(weak reference)试图访问一个已经被垃圾回收机制回收了的对象 |
RuntimeError | 一般的运行时错误 |
StopIteration | 迭代器没有更多的值 |
SyntaxError | Python的语法错误 |
IndentationError | 缩进错误 |
TabError | Tab和空格混合使用 |
SystemError | Python编译器系统错误 |
SystemExit | Python编译器进程被关闭 |
TypeError | 不同类型间的无效操作 |
UnboundLocalError | 访问一个未初始化的本地变量(NameError的子类) |
UnicodeError | Unicode相关的错误(ValueError的子类) |
UnicodeEncodeError | Unicode编码时的错误(UnicodeError的子类) |
UnicodeDecodeError | Unicode解码时的错误(UnicodeError的子类) |
UnicodeTranslateError | Unicode转换时的错误(UnicodeError的子类) |
ValueError | 传入无效的参数 |
ZeroDivisionError | 除数为零 |
以下是python内置异常类的层次结构
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning