10.1 异常处理基础
10.1.1 异常处理机制
10.1.2 基本语法结构
try:
# 可能引发异常的代码
except ExceptionType as e:
# 异常处理代码
else:
# 无异常时执行
finally:
# 无论是否异常都执行
10.2 常见异常类型
10.2.1 内置异常层次
10.2.2 主要异常类型
表10-1 Python常见异常类型
异常类型 | 触发场景 | 示例 |
ValueError | 值无效 | int("abc") |
TypeError | 类型错误 | "a" + 1 |
IndexError | 索引越界 | [1,2][3] |
KeyError | 键不存在 | {}["key"] |
FileNotFoundError | 文件未找到 | open("nonexist.txt") |
ZeroDivisionError | 除零错误 | 1/0 |
AttributeError | 属性错误 | "".no_method() |
10.3 异常处理进阶
10.3.1 多异常处理
try:
# 可能出错的代码
except (ValueError, TypeError) as e:
print(f"输入错误: {e}")
except FileNotFoundError as e:
print(f"文件未找到: {e.filename}")
except Exception as e:
print(f"未知错误: {e}")
10.3.2 异常链与上下文
try:
import nonexistent_module
except ImportError as e:
raise RuntimeError("依赖缺失") from e
10.3.3 自定义异常
class MyAppError(Exception):
"""应用基础异常"""
class InvalidInputError(MyAppError):
"""输入无效异常"""
def __init__(self, input_value):
self.input_value = input_value
super().__init__(f"无效输入: {input_value}")
# 使用示例
def process(data):
if not data.isdigit():
raise InvalidInputError(data)
return int(data)
10.4 调试技术
10.4.1 print调试法
def complex_calculation(a, b):
print(f"输入参数: a={a}, b={b}") # 调试输出
result = a * b
print(f"中间结果: {result}") # 调试输出
result += 100
return result
10.4.2 断言调试
def divide(a, b):
assert b != 0, "除数不能为零"
return a / b
# 触发断言
divide(10, 0) # AssertionError: 除数不能为零
10.4.3 logging模块
import logging
# 配置日志
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s',
filename='app.log'
)
def process_data(data):
logging.debug(f"开始处理数据: {data}")
try:
result = int(data)
logging.info(f"处理成功: {result}")
return result
except ValueError as e:
logging.error(f"处理失败: {e}")
raise
10.5 使用调试器
10.5.1 pdb基本命令
表10-2 pdb常用命令
命令 | 缩写 | 功能 |
break | b | 设置断点 |
continue | c | 继续执行 |
next | n | 单步执行(不进入函数) |
step | s | 单步执行(进入函数) |
where | w | 显示调用栈 |
p | 打印变量 | |
list | l | 显示当前代码 |
quit | q | 退出调试器 |
10.5.2 调试示例
# 在代码中插入断点
import pdb; pdb.set_trace()
# 或者命令行启动
# python -m pdb script.py
10.6 单元测试
10.6.1 unittest示例
import unittest
def add(a, b):
return a + b
class TestAdd(unittest.TestCase):
def test_add_integers(self):
self.assertEqual(add(1, 2), 3)
def test_add_strings(self):
self.assertEqual(add("a", "b"), "ab")
def test_add_type_error(self):
with self.assertRaises(TypeError):
add("a", 1)
if __name__ == "__main__":
unittest.main()
10.6.2 pytest示例
# test_sample.py
import pytest
def test_addition():
assert 1 + 1 == 2
def test_division():
with pytest.raises(ZeroDivisionError):
1 / 0
# 运行测试
# pytest test_sample.py -v
10.7 性能分析
10.7.1 timeit模块
from timeit import timeit
# 测量代码执行时间
time = timeit('"-".join(str(n) for n in range(100))', number=10000)
print(f"执行时间: {time:.4f}秒")
10.7.2 cProfile分析
import cProfile
def slow_function():
return sum(i*i for i in range(1000000))
cProfile.run('slow_function()')
10.8 综合应用举例
案例1:健壮的数据处理器
import logging
from typing import Union
logging.basicConfig(level=logging.INFO)
class DataProcessor:
"""带有完善错误处理的数据处理器"""
def __init__(self, max_retries=3):
self.max_retries = max_retries
def process(self, data: Union[str, int, float]) -> float:
"""处理输入数据返回浮点数"""
for attempt in range(1, self.max_retries + 1):
try:
value = float(data)
if value < 0:
logging.warning(f"负值输入: {value}")
return value
except (ValueError, TypeError) as e:
logging.error(f"尝试 {attempt} 失败: {e}")
if attempt == self.max_retries:
raise InvalidInputError(data) from e
continue
except Exception as e:
logging.critical(f"未知错误: {e}")
raise
# 使用示例
processor = DataProcessor()
try:
result = processor.process("123.45")
print(f"处理结果: {result}")
except InvalidInputError as e:
print(f"处理失败: {e}")
案例2:自动化测试框架
import unittest
from unittest.mock import patch
class TestUserService(unittest.TestCase):
@patch('user_service.Database') # 模拟数据库
def test_user_creation(self, mock_db):
# 设置模拟返回值
mock_db.return_value.insert.return_value = 1001
from user_service import create_user
user_id = create_user("test@example.com", "password123")
# 验证结果
self.assertEqual(user_id, 1001)
mock_db.return_value.insert.assert_called_once_with(
"users", {"email": "test@example.com", "password": "password123"}
)
def test_invalid_email(self):
from user_service import create_user
with self.assertRaises(ValueError):
create_user("invalid-email", "password")
if __name__ == "__main__":
unittest.main()
10.9 学习路线图
10.10 学习总结
- 核心要点:
- 掌握try-except-finally完整结构
- 理解异常类继承体系
- 熟练使用调试工具
- 能够编写单元测试
- 实践建议:
- 异常处理要具体化(避免裸except)
- 使用logging替代print调试
- 重要操作添加断言检查
- 为关键功能编写测试用例
- 进阶方向:
- 异常链与上下文管理
- 异步代码调试
- 性能优化分析
- 测试覆盖率分析
- 常见陷阱:
- 过度捕获异常掩盖问题
- 忘记处理finally中的异常
- 测试用例不够独立
- 调试后遗留的调试代码
持续更新Python编程学习日志与技巧,敬请关注!