异常处理
try/except/finally/else、raise from 链式异常、自定义异常类
异常处理
程序运行时难免出错。异常处理让你优雅地应对错误,而不是让程序崩溃。
学完本章你将掌握: try-except、捕获多种异常、else/finally、raise 抛出、自定义异常。
一、什么是异常
python
# 正常运行
num = int("42")
print(num * 2) # 84
# 但是用户可能输入非数字
# num = int("abc") # ❌ ValueError: invalid literal for int()...
不处理异常,整个程序崩溃。处理了,程序可以继续运行或优雅退出。
二、try-except 基础
python
try:
num = int("abc")
print(num)
except ValueError:
print("无法将 'abc' 转为数字!")
num = 0
print(f"使用默认值: {num}") # 程序继续运行
三、捕获多种异常
python
def safe_divide(a, b):
try:
result = a / b
except ZeroDivisionError:
return "错误:不能除以零!"
except TypeError:
return "错误:类型不正确!"
except Exception as e:
return f"未知错误: {e}"
else:
return f"结果: {result}"
print(safe_divide(10, 2)) # 结果: 5.0
print(safe_divide(10, 0)) # 错误:不能除以零!
print(safe_divide("a", 2)) # 错误:类型不正确!
💡 捕获顺序很重要:把具体的异常(如
ZeroDivisionError)放在前面,通用的(如Exception)放最后。如果顺序反了,具体异常永远不会被触发。
四、else 和 finally
python
# else:无异常时执行
try:
num = int("42")
except ValueError:
print("转换失败")
else:
print(f"转换成功: {num * 2}") # 只在无异常时运行
# finally:无论如何都执行(常用于清理资源)
try:
f = open("data.txt", "r")
content = f.read()
except FileNotFoundError:
print("文件不存在")
finally:
print("操作完成") # 文件存在与否都会执行
# 实际代码中这里应关闭文件
五、常见异常类型
| 异常 | 触发条件 |
|---|---|
| `ValueError` | 值不正确(如 `int("abc")`) |
| `TypeError` | 类型错误(如 `"a" + 1`) |
| `IndexError` | 列表索引越界 |
| `KeyError` | 字典键不存在 |
| `ZeroDivisionError` | 除以零 |
| `FileNotFoundError` | 文件不存在 |
| `AttributeError` | 对象没有该属性 |
| `ImportError` | 导入模块失败 |
python
# 综合示例
def process_data(data, index):
try:
item = data[index]
result = int(item)
return 100 / result
except IndexError:
return "索引超出范围"
except ValueError:
return f"'{item}' 不是数字"
except ZeroDivisionError:
return "不能除以零"
六、raise——主动抛出异常
python
def set_age(age):
if age < 0:
raise ValueError("年龄不能为负数!")
if age > 150:
raise ValueError(f"年龄 {age} 不太合理!")
print(f"年龄设置为 {age}")
set_age(25) # 正常
# set_age(-5) # ❌ ValueError: 年龄不能为负数!
七、自定义异常
python
class InvalidAgeError(ValueError):
"""自定义年龄异常"""
pass
class UnderageError(Exception):
"""未成年人异常"""
pass
def check_entry(age):
if age < 0:
raise InvalidAgeError("年龄无效")
if age < 18:
raise UnderageError("未成年人禁止入内")
return "欢迎光临"
try:
print(check_entry(15))
except UnderageError as e:
print(e) # 未成年人禁止入内
八、实战:安全的输入处理
python
def get_number(prompt):
"""反复要求用户输入,直到得到合法数字"""
while True:
try:
return int(input(prompt))
except ValueError:
print("请输入一个有效的整数!")
# age = get_number("请输入年龄: ")
# 安全读取文件
def safe_read(filename, default=""):
try:
with open(filename, "r", encoding="utf-8") as f:
return f.read()
except FileNotFoundError:
return default
except PermissionError:
return f"没有权限读取 {filename}"
九、traceback——获取详细错误信息
python
import traceback
try:
1 / 0
except ZeroDivisionError:
print("出错了,详细信息:")
traceback.print_exc() # 打印完整调用栈
小结
try-except捕获异常,程序不会崩溃- 按具体→通用的顺序捕获异常
else在无异常时执行,finally无论如何都执行raise主动抛出异常- 可以继承 Exception 创建自定义异常
小练习
- 写一个
safe_int()函数,反复要求输入直到得到合法整数 - 写一个函数打开文件,处理文件不存在和权限错误两种情况
- 创建一个自定义异常
InsufficientBalanceError用于余额不足场景
💬 下一章预告:学完异常处理,下一章学习模块与包——组织和复用代码的最佳方式。