0%

Python之异常

这里介绍Python中的异常

abstract.png

自定义异常

Python中异常的基类为BaseException。其常见子类有:SystemExit、KeyboardInterrupt、Exception等。其中,Exception是常规异常的基类。当我们自定义异常类时,建议直接或间接继承Exception类。而不是直接继承BaseException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 自定义异常类:直接继承 Exception
class CustomException(Exception):
pass


# 自定义异常类:间接继承 Exception
class RuntimeException(ZeroDivisionError):
pass


# 自定义异常类:直接继承 Exception
class BusinessException(Exception):
def __init__(self, code, msg):
super().__init__(self)
self.code = code
self.msg = msg

# 通常建议重写 __str__() 方法,可用于打印异常的信息
def __str__(self):
detail = {
"code": self.code,
"msg": self.msg,
}
return str(detail)

def get_code(self):
return self.code

def get_msg(self):
return self.msg


if __name__ == "__main__":
try:
raise BusinessException(520, "参数校验失败")
except BusinessException as ex:
error_code = ex.get_code()
error_msg = ex.get_msg()
print(f"error code : {error_code}; error msg : {error_msg}")
print("happen business exception:", ex)
except Exception as ex:
print("ex:", ex)

figure 0.jpg

捕获异常

可以通过except子句捕获指定异常。具体地,可以在一个except子句中使用元组指定多个异常;也可以同时使用多个excpet子句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
print("-------------- 捕获异常 -------------")
try:
num = 5/0
except ZeroDivisionError:
print("[#1] 除数不能为0")


# 1. 可以在一个except语句中使用元组指定多个异常
# 2. 可使用多个excpet子句
print("\n\n-------------- 捕获多个异常 -------------")
for i in range(0,2) :
try:
if( i==1 ):
i = "aaron"
answer = 5 / i
except (ZeroDivisionError, SyntaxError) as ex:
# 可使用as语句将异常实例关联到变量上
print("Error: 除数为0, ex:", ex)
except TypeError:
print("发生语法错误")
except :
# 当excpet子句未指定异常类型时,其类型为BaseException异常基类,可捕获所有异常
print("发生异常")

figure 1.png

try-except的finally子句: 无论try中发生任何异常,finally中的代码都会被执行。即使try中发生的异常未被捕获,finally中代码在全部执行完成后,会再次重新抛出相应异常

figure 2.png

抛异常

1. 基本语法

可通过raise子句来抛出异常

1
2
# 抛出异常
raise AttributeError("用户姓名重复")

figure 3.png

2. 异常捕获后继续抛该异常

捕获异常后,可直接使用raise,其会继续抛出当前捕获的异常

1
2
3
4
5
6
try:
num = 5/0
except ZeroDivisionError:
print("[#1] 除数不能为0")
# 捕获异常后,可直接使用raise,其会继续抛出当前捕获的异常
raise

figure 4.png

3. 异常捕获后抛其他异常

捕获异常后,可使用raise抛出其他的异常。此时,导致进入except子句的异常将被作为异常上下文存储起来,并出现在最终的错误消息中

1
2
3
4
5
6
7
try:
num = 5/0
except ZeroDivisionError:
print("[#2] 除数不能为0")
# 捕获异常后,可使用raise抛出别的异常
# 此时,导致进入except子句的异常将被作为异常上下文存储起来,并出现在最终的错误消息中
raise OSError

figure 5.png

4. 异常捕获后抛其他异常,并重设异常上下文

捕获异常后,可使用raise抛出别的异常。同时,使用raise … from … 语句提供指定的异常上下文

1
2
3
4
5
6
7
try:
num = 5/0
except ZeroDivisionError:
print("[#3] 除数不能为0")
# 捕获异常后,可使用raise抛出别的异常
# 同时,使用raise ... from ... 语句提供指定的异常上下文
raise OSError from SyntaxError

figure 6.png

5. 异常捕获后抛其他异常,并清除异常上下文

捕获异常后,可使用raise抛出别的异常。同时,使用raise … from None 语句 清除 异常上下文

1
2
3
4
5
6
7
try:
num = 5/0
except ZeroDivisionError:
print("[#4] 除数不能为0")
# 捕获异常后,可使用raise抛出别的异常
# 同时,使用raise ... from None 语句 清除 异常上下文
raise OSError from None

figure 7.png

其他特性

else子句

try-except支持else子句。仅当try代码块成功执行,未抛出异常,才会执行else代码块

1
2
3
4
5
6
7
8
for i in range(0,3) :
try:
print(f"i --->>> {i}")
answer = 5 / i
except ZeroDivisionError:
print("[Error]: 除数i是0")
else:
print("answer:", answer)

figure 8.png

try-with语句

try-with语句封装了try-except-finally 范式。使得对于需要关闭的资源,不再需要显式地通过finllay子句进行关闭

1
2
3
4
5
6
# as 子句是可选的,用于关联变量
with open("main.txt") as file1, open("readme.txt") as file2:
src = file1.read(60)

print(f"文件file1是否被关闭: {file1.closed}")
print(f"文件file2是否被关闭: {file2.closed}")

figure 9.png

参考文献

  1. Python编程·第3版:从入门到实践 Eric Matthes著
  2. Python基础教程·第3版 Magnus Lie Hetland著
  3. 流畅的Python·第1版 Luciano Ramalho著
请我喝杯咖啡捏~

欢迎关注我的微信公众号:青灯抽丝