异常多指程序在执行的过程中,出现的未知错误,语法和逻辑都是正确的,可以通过其他代码进行处理修复。
错误指没法通过其他的代码进行处理的问题。
常见的系统异常
- 除零异常 ZeroDivisionError
- 名称异常 NameError
- 类型异常 TypeError
- 索引异常 IndexError
- 键异常 KeyError
- 值异常 ValueError
- 属性异常 AttributeError
- 迭代器异常 StopIteration
系统异常类继承树
BaseException 所有内建的异常的基类
- SystemExit 由sys.exit()函数引发。当它不处理时,python 解释器退出
- KeyboardInterrupt 当用户点击中断键(ctrl + C)时引发
- GeneratorExit 当调用一种generator的close()方法时引发
- Exception 所有的内置的,非系统退出异常是从该类派生。应该从该类派生所有用户定义的异常
try:print(name)except NameError:print('名称有问题')
try:
可能会出现异常的代码,这里不管以后会抛出多少个异常,只会从上往下检测,检测到一个后,就会立即往下去匹配,不会多次检测。
try:1/0print(name)except ZeroDivisionError:print('除零异常')except NameError:print('名称有问题')else:print('不出现异常执行')finally:print('最后执行的内容,到时候,不管是否会出现异常,都会执行的语句')
except 你要捕捉的异常类型 as 接收异常的形参:
可以有多个重复,用于捕捉可能的其他异常
try:# 1 / 0print(name)except ZeroDivisionErroras ze:print('除零异常', ze)except NameErroras ne:print('名称有问题', ne)
名称有问题 name ‘name’ is not defined
else:
没出现异常时做的处理,这一块必须放在上一块 except 结束后。
finally:
不管有没有出现异常,都会执行的代码,这一块必须放在最后
try:# 1 / 0print(name)except(ZeroDivisionError, NameError)as e:print('xxx', e)
xxx name ‘name’ is not defined
异常名称不确定,而又想捕捉,可以直接写exception
try:# 1 / 0print(name)except Exceptionas e:print('xxx', e)
xxx name ‘name’ is not defined
with context_expression[as tearet(s)]
适用于执行某一段代码A之前,进行预处理,执行代码A结束后,进行清理操作。不管出现了什么异常,最终都要执行一些清理操作。
withopen('xxx.jpg','r')as f:
f.readlines()
自定义上下文管理器
classTest:def__enter__(self):print('enter')return selfdef__exit__(self, exc_type, exc_val, exc_tb):print(self, exc_type, exc_val, exc_tb)print('exit')with Test()as x:print('body', x)
enter
body <main.Test object at 0x0000020E4AD59B88>
<main.Test object at 0x0000020E4AD59B88> None None None
exit
import tracebackclassTest:def__enter__(self):print('enter')return selfdef__exit__(self, exc_type, exc_val, exc_tb):print(self, exc_type, exc_val, exc_tb)print(traceback.extract_tb(exc_tb))print('exit')returnTruewith Test()as x:# print('body', x)1/0
enter
<main.Test object at 0x000002AD16F08BC8> <class ‘ZeroDivisionError’> division by zero <traceback object at 0x000002AD16F1CC08>
[<FrameSummary file d:\python\python_learn\test.py, line 16 in >]
exit
contextlib 模块
@contextlib.contextmanger 使用装饰器,让一个生成器变成一个上下文管理器
import contextlib
@contextlib.contextmanagerdeftest():"""
docstring
"""print(1)yield'xxx'print(2)with test()as x:print(3, x)
1
3 xxx
2
import contextlib
@contextlib.contextmanagerdefze():try:yieldexcept ZeroDivisionErroras e:print('error', e)
x=1
y=0with ze():
x/ y
error division by zero
contextlib.closing
这个函数,让一个拥有close方法但不是上下文管理器的对象变成上下文管理器
import contextlibclassTest:deft(self):print('ttt')defclose(self):print('资源释放')with contextlib.closing(Test())as t_obj:
t_obj.t()
ttt
资源释放
withopen('xx.jpg','rb')as from_file,open('xx2.jpg','wb')as to_file:
from_contents= from_file.read()
to_file.write(from_contents)
手动抛出异常
通过raise语句直接抛出相关类型的异常
defset_age(age):if age<=0or age>200:raise ValueError('值错误')else:print(age)
set_age(-18)
classLessZero(Exception):def__init__(self, msg)->None:
self.msg= msgdef__str__(self)->str:return'123'defset_age(age):if age<=0or age>200:raise LessZero('值错误')else:print(age)
set_age(-18)
classLessZero(Exception):def__init__(self, msg, error_code)->None:
self.msg= msg
self.ec= error_codedef__str__(self)->str:return self.msg+str(self.ec)defset_age(age):if age<=0or age>200:raise LessZero('小于0值错误',404)else:print(age)try:
set_age(-18)except LessZeroas e:print('x', e)
x 小于0值错误404