在程序运行过程中,错误是不可避免的。为了避免程序在遇到错误时直接崩溃,Python 提供了强大的异常处理机制,使程序具有更好的鲁棒性和用户体验。
7.1 异常的概念
异常(Exception) 是程序运行中发生的错误。与语法错误不同,异常不会在编译阶段报错,而是在执行过程中发生。
常见异常类型:
异常类型 | 描述 |
ZeroDivisionError | 除以零错误 |
ValueError | 错误的数值类型 |
TypeError | 错误的操作数类型 |
FileNotFoundError | 打开不存在的文件 |
IndexError | 列表索引超出范围 |
KeyError | 字典中查找不存在的键 |
NameError | 访问未定义的变量 |
7.2 try-except 语句
Python 使用 try-except 来捕获异常,以避免程序崩溃。
基本语法:
try:
# 尝试执行的代码块
except 异常类型 as 变量:
# 出现异常时执行的代码
示例:
try:
x = int(input("请输入一个整数:"))
result = 10 / x
print("结果为:", result)
except ZeroDivisionError:
print("错误:不能除以 0!")
except ValueError:
print("错误:请输入有效的整数!")
#你可以捕获多个异常,也可以使用通用异常:
try:
#...
except Exception as e:
print("出现了未知错误:", e)
✅ 建议:避免使用 except:,它会捕获所有异常,包括 SystemExit、KeyboardInterrupt 等不应拦截的系统异常。
7.3 异常对象
每个异常都是一个对象。通过 as 语法可以获取这个对象并读取其错误信息。如:
try:
f = open("不存在的文件.txt")
except FileNotFoundError as e:
print("文件打开失败:", e)
异常类的继承体系(简化)
BaseException
├── SystemExit
├── KeyboardInterrupt
└── Exception
├── ArithmeticError
│ ├── ZeroDivisionError
│ └── OverflowError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── FileNotFoundError
├── ValueError
├── TypeError
└── ...
你可以使用 issubclass() 或 help() 函数查看异常的继承关系:
print(issubclass(ZeroDivisionError, ArithmeticError)) # True
7.4 finally 子句
无论是否发生异常,finally 中的代码一定会被执行,常用于资源释放,如关闭文件或断开连接。
示例:
try:
f = open("data.txt", "r")
content = f.read()
except FileNotFoundError as e:
print("文件不存在:", e)
finally:
if 'f' in locals() and not f.closed:
f.close()
print("文件已关闭")
7.5 else 子句(可选)
else 在 try 中没有发生异常时执行。可用于处理“正常情况”的逻辑,使代码结构更清晰。
示例:
try:
number = int(input("请输入一个正整数:"))
assert number > 0
except (ValueError, AssertionError) as e:
print("错误:", e)
else:
print("你输入的是:", number)
7.6 自定义异常
当内置异常不能很好表达业务逻辑时,可以自定义异常类。
定义自定义异常类:
class NegativeNumberError(Exception):
def __init__(self, value):
self.value = value
super().__init__(f"不能输入负数:{value}")
使用自定义异常:
def check_positive(n):
if n < 0:
raise NegativeNumberError(n)
try:
check_positive(-3)
except NegativeNumberError as e:
print("捕获自定义异常:", e)
7.7 异常链(进阶)
Python 支持通过 raise ... from ... 明确新异常由原异常引起,方便调试。
示例:
try:
int("abc")
except ValueError as e:
raise RuntimeError("数据格式错误") from e
此结构保留了原始异常的完整堆栈信息。
7.8 小结
关键词 | 用途 |
try | 放置可能出错的代码块 |
except | 捕获并处理异常 |
else | 当无异常时执行 |
finally | 无论如何都执行 |
raise | 主动引发异常 |
Exception | 所有常规异常的基类 |
✅ 推荐练习题
- 写一个程序,要求用户输入两个整数,尝试做除法,处理除 0 和格式错误。
- 编写一个函数 read_file(filename),如果文件不存在抛出自定义异常 FileMissingError。
- 模拟一个银行取款函数,若余额不足则抛出 InsufficientFundsError。
- 尝试 try-except-else-finally 的多种组合,理解其执行顺序。
- 用 raise ... from ... 创建异常链,观察堆栈信息输出。