1.介绍

异常在程序中无处不在,也无法避免,如果不妥善处理潜在的异常,可能会导致整个程序的退出,在Python中使用try...except来捕获异常,从而避免程序退出或者不能正常运行。

1.1 不捕获示例

# --------------代码部分----------------
def demo(a: int, b: int) -> float:
return a / b

if __name__ == "__main__":
# 不捕获异常示例
res = demo(10, 0)
print("res = ",res)

# --------------输出----------------
Traceback (most recent call last):
File "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/main.py", line 10, in <module>
res = demo(10, 0)
^^^^^^^^^^^
File "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/main.py", line 5, in demo
return a / b
~~^~~
ZeroDivisionError: division by zero

1.2 捕获示例

# --------------代码部分----------------
def demo(a: int, b: int) -> float:
return a / b

if __name__ == "__main__":
# 捕获异常示例
try:
res = demo(10, 0)
except ZeroDivisionError:
res = None
print("不能除以0")

print("res = ", res)

# --------------输出----------------
不能除以0
res = None

2. 捕获语法

2.1 常见语法

Python支持多种组合方式捕获异常,一般我们常见的捕获语法如下:

try:
# 代码逻辑...
except 异常对象:
# 对异常进行处理...

2.2 常见内置异常对象

异常对象 说明
Exception 通用错误,一般都能用
AttributeError 访问某个对象不存在的属性时
FileNotFoundError 文件不存在
IndexError 索引超过范围错误
KeyError 访问字典中不存在的key
ZeroDivisionError 除数为0错误
NameError 访问的变量未曾定义
TypeError 数据类型错误
SyntaxError 代码语法错误

3.捕获异常方式

3.1 try..except

这种方式是最基本的捕获方式,最开始部分已经演示,这里直接跳过。

3.2 加个 else

3.2.1 捕获语法

try:
# 代码逻辑...
except 异常对象:
# 对异常进行处理...
else:
# 代码不发生异常处理...

3.2.2 代码示例

# ------------------- 代码 -------------------
if __name__ == "__main__":
try:
res = demo(10, 2)
except ZeroDivisionError:
res = None
print("不能除以0:")
else:
print("代码运行正常")

print("res = ", res)

# ------------------- 输出 -------------------
# 代码运行正常
# res = 5.0

@示例中的demo函数参见上个示例,这里不在重复.

3.3 多个except

当我们的程序复杂以后,可能会出现各种错误,不一定哪种错误先触发,这个时候我们就需使用多个except去捕获

3.3.1 捕获语法

try:
# 代码逻辑...
except 异常对象A:
# 对异常进行处理...
except 异常对象B:
# 对异常进行处理..
except 异常对象C:
# 对异常进行处理..

3.3.2 代码示例

if __name__ == "__main__":
try:
print("具体代码逻辑.....")
except KeyError:
print("key不存在")
except FileNotFoundError:
print("文件不存在")
except Exception:
print("未知错误")

print("运行完成")

@注:捕获多个异常,也可以使用一个except,如except(异常对象A,异常对象B,…):

3.4 加个finally

3.4.1 捕获语法

try:
# 代码逻辑...
except 异常对象A:
# 对异常进行处理...
finally:
# 不管是否异常都要运行的部分

3.4.2 代码示例

# ------------------- 代码 -------------------
if __name__ == "__main__":
# noinspection PyBroadException
try:
print("打开文件,读取内容..")
demo(1, 0)
except Exception as e:
# 打印错误信息
print("发生未知错误: " + str(e))
finally:
print("关闭文件")

print("运行结束")

# ------------------- 输出 -------------------
# 打开文件,读取内容..
# 发生未知错误: division by zero
# 关闭文件
# 运行结束

4. 抛出异常方式

在开发过程中不但要捕获异常,有时也需要我们主动抛出异常,在Python中,使用关键字raise抛出异常,语法如下:

raise 异常对象("这里写错误信息..")

4.1 抛出内置错误

# -------------------代码 -----------------------
def demo(a: int, b: int) -> float:
if b == 0:
# 抛出异常
raise Exception("参数错误,分母不能为0~")
return a / b


if __name__ == "__main__":
# noinspection PyBroadException
try:
demo(1, 0)
except Exception as e:
# 打印错误信息
print("运行异常: " + str(e))

print("运行结束")

# -------------------输出 -----------------------
# 运行异常: 参数错误,分母不能为0~
# 运行结束

4.2 抛出自定义错误

在实际开发过程中,有时我们需要抛出自定义的错误,用来和内置错误进行区分,示例代码如下:

# ------------------- 自定义错误 -----------------------
# 自定义错误,继承父类
class MyError(Exception):
pass

# ------------------- 修改上面示例 -----------------------
def demo(a: int, b: int) -> float:
if b == 0:
# 抛出异常
raise MyError("参数错误,分母不能为0~")
return a / b


if __name__ == "__main__":
# noinspection PyBroadException
try:
demo(1, 0)
except MyError as e:
# 打印错误信息
print("运行异常: " + str(e))

print("运行结束")

# -------------------输出 -----------------------
# 运行异常: 参数错误,分母不能为0~
# 运行结束

5. 具体错误位置

有时候虽然我们捕获了异常,但是却不能准确的定位到具体哪一行代码,Python提供了traceback包,用来解决这个问题。

5.1 使用示例

# -------------------文件: basis/error.py -----------------------   
from common import demo

def testError(a: int, b: int) -> float:
print("运行到testError;a :{} b:{}".format(a, b))
add = a + a
return demo.divide(add, b)

# -------------------文件: common/demo.py -----------------------
def divide(a: int, b: int) -> float:
print("运行到divide;a :{} b:{}".format(a, b))
if b == 0:
# 抛出异常
raise Exception("参数错误,分母不能为0~")
return a / b

# --------------------------main.py ------------------------------
import traceback

from basis import error

if __name__ == "__main__":
# noinspection PyBroadException
try:
r = error.testError(10, 0)
print(r)
except Exception as e:
# 打印错误信息
print("运行异常: ", traceback.format_exc())

print("运行结束")

# --------------------------输出 ------------------------------
运行到testError;a :10 b:0
运行到divide;a :20 b:0
运行异常: Traceback (most recent call last):
File "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/main.py", line 8, in <module>
r = error.testError(10, 0)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/basis/error.py", line 15, in testError
return demo.divide(add, b)
^^^^^^^^^^^^^^^^^^^
File "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/common/demo.py", line 15, in divide
raise Exception("参数错误,分母不能为0~")
Exception: 参数错误,分母不能为0~