异常多指程序在执行的过程中,出现的未知错误,语法和逻辑都是正确的,可以通过其他代码进行处理修复。
错误指没法通过其他的代码进行处理的问题。
常见的系统异常
- 除零异常 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 / 0
print(name)
except ZeroDivisionError:
print('除零异常')
except NameError:
print('名称有问题')
else:
print('不出现异常执行')
finally:
print('最后执行的内容,到时候,不管是否会出现异常,都会执行的语句')
except 你要捕捉的异常类型 as 接收异常的形参:
可以有多个重复,用于捕捉可能的其他异常
try:
# 1 / 0
print(name)
except ZeroDivisionError as ze:
print('除零异常', ze)
except NameError as ne:
print('名称有问题', ne)
名称有问题 name ‘name’ is not defined
else:
没出现异常时做的处理,这一块必须放在上一块 except 结束后。
finally:
不管有没有出现异常,都会执行的代码,这一块必须放在最后
try:
# 1 / 0
print(name)
except (ZeroDivisionError, NameError) as e:
print('xxx', e)
xxx name ‘name’ is not defined
异常名称不确定,而又想捕捉,可以直接写exception
try:
# 1 / 0
print(name)
except Exception as e:
print('xxx', e)
xxx name ‘name’ is not defined
with context_expression[as tearet(s)]
适用于执行某一段代码A之前,进行预处理,执行代码A结束后,进行清理操作。不管出现了什么异常,最终都要执行一些清理操作。
with open('xxx.jpg', 'r') as f:
f.readlines()
自定义上下文管理器
class Test:
def __enter__(self):
print('enter')
return self
def __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 traceback
class Test:
def __enter__(self):
print('enter')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print(self, exc_type, exc_val, exc_tb)
print(traceback.extract_tb(exc_tb))
print('exit')
return True
with 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.contextmanager
def test():
"""
docstring
"""
print(1)
yield 'xxx'
print(2)
with test() as x:
print(3, x)
1
3 xxx
2
import contextlib
@contextlib.contextmanager
def ze():
try:
yield
except ZeroDivisionError as e:
print('error', e)
x = 1
y = 0
with ze():
x / y
error division by zero
contextlib.closing
这个函数,让一个拥有close方法但不是上下文管理器的对象变成上下文管理器
import contextlib
class Test:
def t(self):
print('ttt')
def close(self):
print('资源释放')
with contextlib.closing(Test()) as t_obj:
t_obj.t()
ttt
资源释放
with open('xx.jpg','rb') as from_file, open('xx2.jpg', 'wb') as to_file:
from_contents = from_file.read()
to_file.write(from_contents)
手动抛出异常
通过raise语句直接抛出相关类型的异常
def set_age(age):
if age <= 0 or age > 200:
raise ValueError('值错误')
else:
print(age)
set_age(-18)
class LessZero(Exception):
def __init__(self, msg) -> None:
self.msg = msg
def __str__(self) -> str:
return '123'
def set_age(age):
if age <= 0 or age > 200:
raise LessZero('值错误')
else:
print(age)
set_age(-18)
class LessZero(Exception):
def __init__(self, msg, error_code) -> None:
self.msg = msg
self.ec = error_code
def __str__(self) -> str:
return self.msg + str(self.ec)
def set_age(age):
if age <= 0 or age > 200:
raise LessZero('小于0值错误', 404)
else:
print(age)
try:
set_age(-18)
except LessZero as e:
print('x', e)
x 小于0值错误404