Skip to content

调试和性能分析 ​

调试发现和修复错误,性能分析识别瓶颈。Python 提供丰富的工具。

最简单的调试方法:

python
def calculate(a, b):
    print(f"calculate called with a={a}, b={b}")
    result = a * b + 10
    print(f"result={result}")
    return result

calculate(5, 3)
# 输出:
# calculate called with a=5, b=3
# result=25

局限:污染代码、难以移除、不够强大。

logging 模块 ​

结构化日志,支持级别控制:

python
import logging

# 配置
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

def process_data(data):
    logging.debug(f"Processing {len(data)} items")
    result = []
    for item in data:
        logging.debug(f"Processing item: {item}")
        result.append(item * 2)
    logging.info(f"Processed {len(result)} items")
    return result

process_data([1, 2, 3])

日志级别:

  • DEBUG:详细信息
  • INFO:一般信息
  • WARNING:警告
  • ERROR:错误
  • CRITICAL:严重错误

pdb 交互式调试器 ​

Python 内置调试器:

python
import pdb

def divide(a, b):
    pdb.set_trace()  # 设置断点
    result = a / b
    return result

divide(10, 2)

pdb 命令:

  • n (next):下一行
  • s (step):进入函数
  • c (continue):继续执行
  • p variable:打印变量
  • l (list):显示代码
  • q (quit):退出

breakpoint()(Python 3.7+) ​

更简洁的断点:

python
def calculate(a, b):
    result = a * b
    breakpoint()  # 自动进入 pdb
    return result

等价于 import pdb; pdb.set_trace(),但更简洁。

IDE 调试器 ​

VS Code ​

  1. 设置断点(点击行号左侧)
  2. 按 F5 启动调试
  3. 使用工具栏控制执行

PyCharm ​

  1. 设置断点
  2. 右键 → Debug
  3. 查看变量、调用栈

优点:可视化、变量监视、条件断点。

性能分析:cProfile ​

分析函数调用时间:

python
import cProfile
import pstats

def slow_function():
    total = 0
    for i in range(1000000):
        total += i
    return total

def main():
    result1 = slow_function()
    result2 = slow_function()
    return result1 + result2

# 性能分析
cProfile.run('main()', 'profile_stats')

# 查看结果
stats = pstats.Stats('profile_stats')
stats.sort_stats('cumulative')
stats.print_stats(10)

输出:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.284    0.284 <string>:1(<module>)
        1    0.000    0.000    0.284    0.284 example.py:9(main)
        2    0.284    0.142    0.284    0.142 example.py:3(slow_function)

性能分析:timeit ​

精确测量小段代码:

python
import timeit

# 方法 1:列表推导
time1 = timeit.timeit('[x**2 for x in range(1000)]', number=10000)

# 方法 2:map
time2 = timeit.timeit('list(map(lambda x: x**2, range(1000)))', number=10000)

print(f"列表推导: {time1:.4f}s")
print(f"map: {time2:.4f}s")

内存分析:memory_profiler ​

分析内存使用:

bash
pip install memory_profiler
python
# example.py
from memory_profiler import profile

@profile
def create_large_list():
    large_list = [i for i in range(1000000)]
    return large_list

@profile
def main():
    data = create_large_list()
    processed = [x * 2 for x in data]
    return processed

if __name__ == '__main__':
    main()

运行:

bash
python -m memory_profiler example.py

输出:

Line #    Mem usage    Increment   Line Contents
================================================
     3   38.1 MiB     38.1 MiB   @profile
     4                             def create_large_list():
     5   76.3 MiB     38.2 MiB       large_list = [i for i in range(1000000)]
     6   76.3 MiB      0.0 MiB       return large_list

实战案例:定位性能瓶颈 ​

python
import cProfile
import time

def slow_computation():
    """模拟慢操作"""
    time.sleep(0.1)
    return sum(range(100000))

def fast_computation():
    """快速操作"""
    return sum(range(100))

def main():
    results = []
    for _ in range(10):
        results.append(slow_computation())
    for _ in range(100):
        results.append(fast_computation())
    return results

# 性能分析
cProfile.run('main()', sort='cumulative')

分析:

  1. 运行 cProfile
  2. 查看 tottime(函数自身时间)
  3. 找到最慢的函数
  4. 优化瓶颈

调试技巧 ​

1. 二分查找错误 ​

python
def complex_function():
    step1()
    print("Step 1 done")  # 检查点
    step2()
    print("Step 2 done")
    step3()
    print("Step 3 done")

2. 断言检查 ​

python
def process(data):
    assert isinstance(data, list), "data must be a list"
    assert len(data) > 0, "data cannot be empty"
    # 继续处理

3. 日志而非 print ​

python
# 不好
print("Debug info:", value)

# 好
logging.debug("Processing value: %s", value)

小结 ​

  • print 简单但有限
  • logging 结构化、可配置
  • pdb/breakpoint() 交互式调试
  • IDE 调试器 可视化、强大
  • cProfile 函数级性能分析
  • timeit 精确测量小段代码
  • memory_profiler 内存使用分析

下一节学习 打包和发布。


参考:

练习:答案

用心记录每一步成长