最近更新:Python中级教程 第六课:高级特性与性能优化 1/2
2026-01-15
最近更新:Python中级教程 第五课:异步编程与并发 2/2
2026-01-15
最近更新:Python中级教程 第五课:异步编程与并发 1/2
2026-01-15
最近更新:Python中级教程 第四课:上下文管理器、生成器与迭代器
2026-01-15
最近更新:Python中级教程 第三课:面向对象编程深入与装饰器
2026-01-15
浏览量:13 次 发布时间:2026-01-15 18:06 作者:明扬工控商城 下载docx
最近更新:Python中级教程 第六课:高级特性与性能优化 1/2
2026-01-15
最近更新:Python中级教程 第五课:异步编程与并发 2/2
2026-01-15
最近更新:Python中级教程 第五课:异步编程与并发 1/2
2026-01-15
最近更新:Python中级教程 第四课:上下文管理器、生成器与迭代器
2026-01-15
最近更新:Python中级教程 第三课:面向对象编程深入与装饰器
2026-01-15
第五部分:测试与调试技巧
5.1 单元测试
python
# test_example.py
import unittest
import sys
import os
# 要测试的模块
class Calculator:
"""简单的计算器类"""
def __init__(self):
self.history = []
def add(self, a, b):
"""加法"""
result = a + b
self.history.append(f"{a} + {b} = {result}")
return result
def subtract(self, a, b):
"""减法"""
result = a - b
self.history.append(f"{a} - {b} = {result}")
return result
def multiply(self, a, b):
"""乘法"""
result = a * b
self.history.append(f"{a} × {b} = {result}")
return result
def divide(self, a, b):
"""除法"""
if b == 0:
raise ValueError("除数不能为零")
result = a / b
self.history.append(f"{a} ÷ {b} = {result}")
return result
def get_history(self):
"""获取历史记录"""
return self.history
def clear_history(self):
"""清除历史记录"""
self.history.clear()
# 测试类
class TestCalculator(unittest.TestCase):
"""Calculator类的测试用例"""
def setUp(self):
"""每个测试方法前执行"""
self.calc = Calculator()
print(f"\n开始测试: {self._testMethodName}")
def tearDown(self):
"""每个测试方法后执行"""
print(f"测试完成: {self._testMethodName}")
# 测试加法
def test_add_integers(self):
"""测试整数加法"""
result = self.calc.add(3, 4)
self.assertEqual(result, 7)
def test_add_floats(self):
"""测试浮点数加法"""
result = self.calc.add(3.5, 2.1)
self.assertAlmostEqual(result, 5.6, places=2)
def test_add_negative(self):
"""测试负数加法"""
result = self.calc.add(-3, 4)
self.assertEqual(result, 1)
# 测试减法
def test_subtract_integers(self):
"""测试整数减法"""
result = self.calc.subtract(10, 4)
self.assertEqual(result, 6)
def test_subtract_negative_result(self):
"""测试结果为负的减法"""
result = self.calc.subtract(3, 7)
self.assertEqual(result, -4)
# 测试乘法
def test_multiply_integers(self):
"""测试整数乘法"""
result = self.calc.multiply(3, 4)
self.assertEqual(result, 12)
def test_multiply_by_zero(self):
"""测试乘以零"""
result = self.calc.multiply(5, 0)
self.assertEqual(result, 0)
# 测试除法
def test_divide_integers(self):
"""测试整数除法"""
result = self.calc.divide(10, 2)
self.assertEqual(result, 5)
def test_divide_floats(self):
"""测试浮点数除法"""
result = self.calc.divide(5, 2)
self.assertEqual(result, 2.5)
def test_divide_by_zero(self):
"""测试除以零"""
with self.assertRaises(ValueError) as context:
self.calc.divide(5, 0)
self.assertEqual(str(context.exception), "除数不能为零")
# 测试历史记录
def test_history(self):
"""测试历史记录功能"""
self.calc.add(1, 2)
self.calc.subtract(5, 3)
self.calc.multiply(2, 3)
history = self.calc.get_history()
self.assertEqual(len(history), 3)
self.assertIn("1 + 2 = 3", history)
self.assertIn("5 - 3 = 2", history)
self.assertIn("2 × 3 = 6", history)
def test_clear_history(self):
"""测试清除历史记录"""
self.calc.add(1, 2)
self.calc.clear_history()
self.assertEqual(len(self.calc.get_history()), 0)
# 参数化测试示例(使用subTest)
def test_add_parameterized(self):
"""参数化测试加法"""
test_cases = [
(1, 2, 3),
(-1, 1, 0),
(0, 0, 0),
(100, 200, 300),
(2.5, 3.5, 6.0)
]
for a, b, expected in test_cases:
with self.subTest(a=a, b=b, expected=expected):
result = self.calc.add(a, b)
self.assertEqual(result, expected)
# 跳过测试
@unittest.skip("暂时跳过这个测试")
def test_skip_example(self):
"""跳过测试示例"""
self.fail("这个测试应该被跳过")
@unittest.skipIf(sys.version_info < (3, 7), "需要Python 3.7或更高版本")
def test_skip_if_example(self):
"""条件跳过测试示例"""
result = self.calc.add(3, 4)
self.assertEqual(result, 7)
# 模拟对象测试
class TestWithMock(unittest.TestCase):
"""使用模拟对象的测试"""
def test_file_operations_with_mock(self):
"""测试文件操作(使用模拟)"""
from unittest.mock import mock_open, patch
# 模拟文件内容
mock_content = "line1\nline2\nline3"
with patch('builtins.open', mock_open(read_data=mock_content)):
with open('test.txt', 'r') as f:
content = f.read()
self.assertEqual(content, mock_content)
def test_api_call_with_mock(self):
"""测试API调用(使用模拟)"""
from unittest.mock import MagicMock, patch
import requests
# 创建模拟响应
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {'success': True, 'data': 'test'}
# 模拟requests.get
with patch('requests.get', return_value=mock_response):
response = requests.get('https://api.example.com/data')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()['success'], True)
# 性能测试
class TestPerformance(unittest.TestCase):
"""性能测试"""
def test_performance_of_algorithm(self):
"""算法性能测试"""
import time
# 测试不同算法的性能
n = 10000
# 测试列表生成
start_time = time.time()
list_comp = [i**2 for i in range(n)]
list_comp_time = time.time() - start_time
start_time = time.time()
map_result = list(map(lambda x: x**2, range(n)))
map_time = time.time() - start_time
# 验证结果相同
self.assertEqual(list_comp, map_result)
# 性能断言(可选的)
if list_comp_time < map_time:
print(f"列表推导式更快: {list_comp_time:.6f} vs {map_time:.6f}")
else:
print(f"map函数更快: {map_time:.6f} vs {list_comp_time:.6f}")
# 集成测试
class TestIntegration(unittest.TestCase):
"""集成测试"""
def test_calculator_integration(self):
"""计算器集成测试"""
calc = Calculator()
# 执行一系列操作
result1 = calc.add(10, 5) # 15
result2 = calc.subtract(result1, 3) # 12
result3 = calc.multiply(result2, 2) # 24
result4 = calc.divide(result3, 4) # 6
self.assertEqual(result4, 6)
# 验证历史记录
history = calc.get_history()
self.assertEqual(len(history), 4)
self.assertIn("10 + 5 = 15", history)
self.assertIn("15 - 3 = 12", history)
self.assertIn("12 × 2 = 24", history)
self.assertIn("24 ÷ 4 = 6", history)
# 测试套件
def create_test_suite():
"""创建测试套件"""
suite = unittest.TestSuite()
# 添加测试类
suite.addTest(unittest.makeSuite(TestCalculator))
suite.addTest(unittest.makeSuite(TestWithMock))
suite.addTest(unittest.makeSuite(TestPerformance))
suite.addTest(unittest.makeSuite(TestIntegration))
return suite
# 运行测试
if __name__ == '__main__':
# 方式1: 使用unittest.main()
# unittest.main(verbosity=2)
# 方式2: 使用测试套件
runner = unittest.TextTestRunner(verbosity=2)
# 运行所有测试
print("=== 运行所有测试 ===")
all_suite = unittest.defaultTestLoader.discover('.', pattern='test_*.py')
runner.run(all_suite)
# 运行特定测试类
print("\n=== 运行Calculator测试 ===")
calc_suite = unittest.TestLoader().loadTestsFromTestCase(TestCalculator)
runner.run(calc_suite)
# 运行单个测试方法
print("\n=== 运行单个测试方法 ===")
single_test = TestCalculator('test_add_integers')
runner.run(unittest.TestSuite([single_test]))
5.2 调试技巧
python
# debugging_examples.py
import pdb
import logging
import traceback
import sys
import inspect
# 1. 使用print调试
def debug_with_print():
"""使用print语句调试"""
print("=== 使用print调试 ===")
def calculate_stats(numbers):
# 添加print语句查看变量值
print(f"输入: {numbers}")
if not numbers:
print("输入为空")
return None
total = sum(numbers)
print(f"总和: {total}")
average = total / len(numbers)
print(f"平均值: {average}")
return {'total': total, 'average': average}
# 测试
data = [1, 2, 3, 4, 5]
result = calculate_stats(data)
print(f"结果: {result}")
# 2. 使用pdb调试器
def debug_with_pdb():
"""使用pdb调试器"""
print("\n=== 使用pdb调试 ===")
def complex_calculation(a, b):
# 设置断点
# pdb.set_trace() # 取消注释以使用
result = 0
for i in range(a):
for j in range(b):
# 这里可能会出错
try:
result += i / (j + 1)
except ZeroDivisionError:
print(f"零除错误: i={i}, j={j}")
# pdb.post_mortem() # 进入事后调试
return result
# pdb常用命令:
# h(elp) - 显示帮助
# n(ext) - 执行下一行
# s(tep) - 进入函数
# c(ontinue) - 继续执行到下一个断点
# l(ist) - 显示当前代码
# p - 打印变量
# q(uit) - 退出调试器
print("取消注释pdb.set_trace()来使用调试器")
# 3. 使用logging调试
def debug_with_logging():
"""使用logging模块调试"""
print("\n=== 使用logging调试 ===")
# 配置logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('debug.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def process_data(data):
logger.debug(f"开始处理数据: {data}")
if not data:
logger.warning("数据为空")
return None
try:
total = sum(data)
logger.debug(f"计算总和: {total}")
average = total / len(data)
logger.debug(f"计算平均值: {average}")
return {'total': total, 'average': average}
except Exception as e:
logger.error(f"处理数据时出错: {e}", exc_info=True)
return None
# 测试
data = [10, 20, 30, 40, 50]
result = process_data(data)
logger.info(f"处理结果: {result}")
# 测试错误情况
process_data([])
# 4. 异常处理与调试
def debug_with_exceptions():
"""使用异常处理调试"""
print("\n=== 异常处理调试 ===")
def divide_numbers(a, b):
try:
result = a / b
return result
except ZeroDivisionError as e:
print(f"零除错误: {e}")
print(f"堆栈跟踪:")
traceback.print_exc()
return None
except TypeError as e:
print(f"类型错误: {e}")
return None
# 测试
print(f"正常情况: {divide_numbers(10, 2)}")
print(f"零除错误: {divide_numbers(10, 0)}")
print(f"类型错误: {divide_numbers(10, '2')}")
# 5. 使用断言调试
def debug_with_assertions():
"""使用断言调试"""
print("\n=== 使用断言调试 ===")
def calculate_discount(price, discount_percent):
# 前置条件断言
assert price > 0, f"价格必须大于0,实际: {price}"
assert 0 <= discount_percent <= 100, f"折扣必须在0-100之间,实际: {discount_percent}"
discount_amount = price * (discount_percent / 100)
final_price = price - discount_amount
# 后置条件断言
assert final_price >= 0, f"最终价格不能为负,实际: {final_price}"
assert final_price <= price, f"最终价格不能高于原价,实际: {final_price}"
return final_price
# 测试
try:
print(f"正常折扣: {calculate_discount(100, 20):.2f}")
print(f"全价: {calculate_discount(100, 0):.2f}")
# 这些会触发断言
# calculate_discount(-100, 20) # 价格不能为负
# calculate_discount(100, 150) # 折扣超出范围
except AssertionError as e:
print(f"断言错误: {e}")
# 6. 代码性能调试
def debug_performance():
"""性能调试"""
print("\n=== 性能调试 ===")
import time
import cProfile
import pstats
import io
def slow_function(n):
"""性能较差的函数"""
result = []
for i in range(n):
for j in range(n):
result.append((i, j, i * j))
return result
def fast_function(n):
"""性能较好的函数"""
result = [(i, j, i * j) for i in range(n) for j in range(n)]
return result
# 使用time测量
print("使用time测量:")
n = 100
start = time.time()
slow_result = slow_function(n)
slow_time = time.time() - start
print(f"慢函数: {slow_time:.4f}秒,结果数: {len(slow_result)}")
start = time.time()
fast_result = fast_function(n)
fast_time = time.time() - start
print(f"快函数: {fast_time:.4f}秒,结果数: {len(fast_result)}")
# 使用cProfile分析
print("\n使用cProfile分析慢函数:")
profiler = cProfile.Profile()
profiler.enable()
slow_function(50) # 使用较小的n避免运行太久
profiler.disable()
# 输出分析结果
stats_stream = io.StringIO()
stats = pstats.Stats(profiler, stream=stats_stream).sort_stats('cumulative')
stats.print_stats(10) # 显示前10个
print(stats_stream.getvalue())
# 7. 内存使用调试
def debug_memory():
"""内存使用调试"""
print("\n=== 内存使用调试 ===")
import sys
import gc
class MemoryIntensive:
def __init__(self, size):
self.data = [i for i in range(size)]
def __repr__(self):
return f"MemoryIntensive(size={len(self.data)})"
def check_memory():
"""检查内存使用"""
print("创建对象前内存使用:")
for obj in gc.get_objects():
if isinstance(obj, MemoryIntensive):
print(f" 找到: {obj}, 大小: {sys.getsizeof(obj)}字节")
# 创建大对象
print("\n创建大对象...")
big_obj = MemoryIntensive(1000000)
print(f"对象大小: {sys.getsizeof(big_obj)}字节")
print(f"对象数据大小: {sys.getsizeof(big_obj.data)}字节")
# 删除对象
print("\n删除对象...")
del big_obj
# 强制垃圾回收
gc.collect()
print("垃圾回收后,再次检查...")
found = False
for obj in gc.get_objects():
if isinstance(obj, MemoryIntensive):
print(f" 仍存在: {obj}")
found = True
if not found:
print(" 对象已正确释放")
check_memory()
# 8. 交互式调试工具
def interactive_debugging():
"""交互式调试"""
print("\n=== 交互式调试工具 ===")
# 使用inspect模块
def example_function(a, b, c=10, *args, **kwargs):
"""示例函数"""
result = a + b + c + sum(args)
return result
print("使用inspect模块:")
# 获取函数签名
sig = inspect.signature(example_function)
print(f"函数签名: {sig}")
# 获取参数信息
print("参数信息:")
for name, param in sig.parameters.items():
print(f" {name}: {param}")
# 获取源代码
print("\n函数源代码:")
print(inspect.getsource(example_function))
# 获取调用栈
print("\n当前调用栈:")
for frame_info in inspect.stack()[:3]: # 只显示前3层
print(f" 文件: {frame_info.filename}, 行: {frame_info.lineno}, 函数: {frame_info.function}")
# 9. 自定义调试装饰器
def create_debug_decorator():
"""创建调试装饰器"""
print("\n=== 自定义调试装饰器 ===")
import functools
import time
def debug_decorator(func):
"""调试装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"\n调用函数: {func.__name__}")
print(f"参数: args={args}, kwargs={kwargs}")
start_time = time.time()
try:
result = func(*args, **kwargs)
end_time = time.time()
print(f"返回值: {result}")
print(f"执行时间: {end_time - start_time:.6f}秒")
return result
except Exception as e:
end_time = time.time()
print(f"异常: {e}")
print(f"执行时间: {end_time - start_time:.6f}秒")
raise
return wrapper
# 使用装饰器
@debug_decorator
def example_debug_function(x, y, operation='add'):
"""示例函数"""
if operation == 'add':
return x + y
elif operation == 'multiply':
return x * y
else:
raise ValueError(f"未知操作: {operation}")
# 测试
print("正常调用:")
result1 = example_debug_function(10, 20, operation='add')
print(f"结果: {result1}")
print("\n乘法调用:")
result2 = example_debug_function(10, 20, operation='multiply')
print(f"结果: {result2}")
print("\n错误调用:")
try:
example_debug_function(10, 20, operation='divide')
except ValueError as e:
print(f"捕获异常: {e}")
# 主程序
if __name__ == "__main__":
print("=== Python调试技巧示例 ===")
# 运行各个示例
debug_with_print()
debug_with_pdb()
debug_with_logging()
debug_with_exceptions()
debug_with_assertions()
debug_performance()
debug_memory()
interactive_debugging()
create_debug_decorator()
print("\n=== 调试技巧总结 ===")
print("1. print: 最简单的调试方法,适合快速查看变量值")
print("2. pdb: 强大的交互式调试器,适合复杂调试")
print("3. logging: 适合生产环境的调试,可以记录到文件")
print("4. 异常处理: 捕获和处理异常,获取详细错误信息")
print("5. 断言: 验证代码假设,及早发现错误")
print("6. 性能分析: 使用time和cProfile分析性能瓶颈")
print("7. 内存调试: 跟踪内存使用,发现内存泄漏")
print("8. 交互式工具: 使用inspect等工具动态检查代码")
print("9. 自定义装饰器: 创建可重用的调试工具")
第六部分:项目结构与代码组织
将本文的Word文档下载到电脑
推荐度: