跳转至

03 - 调试与问题解决能力

目标:能独立定位和修复bug,不依赖AI

时间:1周

核心原则:调试是编程的核心技能,必须掌握


🐛 为什么调试能力重要?

现实场景

Text Only
场景1:代码报错
新手:"这段代码报错了,帮我修一下"(直接问AI)
老手:"我看看错误信息... 哦,是索引越界了"

场景2:程序结果不对
新手:"结果不对,哪里错了?"(直接问AI)
老手:"我加几个print看看中间值... 找到问题了"

场景3:程序卡住
新手:"程序没反应,怎么办?"(直接问AI)
老手:"我检查一下是不是死循环..."

调试能力 = 独立解决问题能力

  • ✅ 不依赖AI,自己定位问题
  • ✅ 快速修复bug
  • ✅ 预防类似问题
  • ✅ 深入理解代码逻辑

🎯 调试方法论

方法1:科学调试法

Text Only
1. 收集证据
   ↓ 观察现象,记录错误信息
2. 提出假设
   ↓ 猜测可能的原因
3. 验证假设
   ↓ 设计实验验证
4. 定位问题
   ↓ 找到根本原因
5. 修复验证
   ↓ 修复并测试

方法2:分而治之

Python
# 问题代码
def complex_function(data):
    result = step1(data)      # 可能出错
    result = step2(result)    # 可能出错
    result = step3(result)    # 可能出错
    return result

# 调试方法:分段测试
print("After step1:", step1(data))
print("After step2:", step2(step1(data)))
print("After step3:", step3(step2(step1(data))))

方法3:最小复现

Text Only
原则:用最少的代码复现问题

错误做法:
- 在一个大项目中找bug
- 依赖复杂的环境

正确做法:
- 把问题代码抽出来
- 用最简单的输入复现
- 排除无关因素

🛠️ 调试工具与技术

技术1:print调试法

最简单但最有效的调试方法:

Python
def calculate_average(numbers):
    print(f"Input: {numbers}")  # 查看输入

    if not numbers:
        print("Empty list!")  # 检查边界
        return 0

    total = sum(numbers)
    print(f"Sum: {total}")  # 查看中间值

    count = len(numbers)
    print(f"Count: {count}")  # 查看中间值

    average = total / count
    print(f"Average: {average}")  # 查看结果

    return average

技术2:断言(assert)

在关键点检查假设:

Python
def divide(a, b):
    assert b != 0, "除数不能为0"
    assert isinstance(a, (int, float)), "a必须是数字"
    assert isinstance(b, (int, float)), "b必须是数字"

    return a / b

# 使用
divide(10, 0)  # AssertionError: 除数不能为0

技术3:日志记录

比print更专业的调试方法:

Python
import logging

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

def process_data(data):
    logging.debug(f"开始处理数据: {data}")

    try:  # try/except捕获异常
        result = step1(data)
        logging.info(f"步骤1完成: {result}")

        result = step2(result)
        logging.info(f"步骤2完成: {result}")

    except Exception as e:
        logging.error(f"处理失败: {e}")
        raise

    logging.debug(f"处理完成: {result}")
    return result

技术4:使用IDE调试器

VS Code调试基础:

Text Only
1. 设置断点:点击行号左侧
2. 启动调试:F5
3. 单步执行:
   - F10:单步跳过(不进入函数)
   - F11:单步进入(进入函数)
   - Shift+F11:单步跳出
4. 查看变量:左侧变量面板
5. 条件断点:右键断点设置条件

📝 常见错误与调试

错误类型1:语法错误

Python
# 错误代码
if x > 5
    print("x is big")

# 错误信息
# SyntaxError: expected ':'

# 调试方法
# 1. 看错误提示的行号
# 2. 检查语法(漏了冒号、括号不匹配等)

错误类型2:运行时错误

Python
# 错误代码
def get_element(arr, index):
    return arr[index]

get_element([1, 2, 3], 5)

# 错误信息
# IndexError: list index out of range

# 调试方法
# 1. 打印arr和index的值
# 2. 检查index是否在有效范围
# 3. 添加边界检查

修复

Python
def get_element(arr, index):
    print(f"Array: {arr}, Index: {index}, Length: {len(arr)}")

    if index < 0 or index >= len(arr):
        print(f"Error: Index {index} out of range [0, {len(arr)-1}]")
        return None

    return arr[index]

错误类型3:逻辑错误

Python
# 错误代码:计算1到n的和
def sum_n(n):
    total = 0
    for i in range(n):  # 错误:应该是range(1, n+1)
        total += i
    return total

print(sum_n(5))  # 期望15,实际10

# 调试方法
# 1. 手动计算期望结果
# 2. 打印每次循环的值
# 3. 对比找出差异

调试

Python
def sum_n(n):
    total = 0
    for i in range(n):
        print(f"i={i}, total={total}")  # 查看循环过程
        total += i
    print(f"Final total: {total}")
    return total

sum_n(5)
# 输出:
# i=0, total=0
# i=1, total=0
# i=2, total=1
# i=3, total=3
# i=4, total=6
# Final total: 10
# 发现:i从0开始,不是从1开始

错误类型4:类型错误

Python
# 错误代码
def add(a, b):
    return a + b

add("5", 3)  # TypeError: can only concatenate str to str

# 调试方法
# 1. 打印参数类型
# 2. 添加类型检查

修复

Python
def add(a, b):
    print(f"a={a}, type={type(a)}")
    print(f"b={b}, type={type(b)}")

    if not isinstance(a, (int, float)):
        a = float(a)
    if not isinstance(b, (int, float)):
        b = float(b)

    return a + b


🎓 调试实战练习

练习1:找出并修复bug

Python
def find_max_index(arr):
    """找出数组中最大值的索引"""
    max_index = 0
    for i in range(len(arr)):
        if arr[i] > arr[max_index]:
            max_index = i
    return max_index

# 测试
print(find_max_index([3, 1, 4, 1, 5, 9, 2, 6]))  # 期望5,实际?

你的任务: 1. 先不看答案,自己找出bug 2. 用print调试 3. 修复bug

练习2:复杂bug调试

Python
def flatten(nested_list):
    """将嵌套列表展平"""
    result = []
    for item in nested_list:
        if isinstance(item, list):  # isinstance检查对象类型
            result.extend(flatten(item))
        else:
            result.append(item)
    return result

# 测试
test = [1, [2, 3], [4, [5, 6]], 7]
print(flatten(test))  # 期望[1, 2, 3, 4, 5, 6, 7]

问题:如果输入包含非列表可迭代对象(如字符串),会怎样?

练习3:性能问题调试

Python
def fibonacci(n):
    """计算斐波那契数列第n项"""
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# 测试
print(fibonacci(35))  # 很慢!

问题:为什么慢?如何优化?

调试

Python
call_count = 0

def fibonacci(n):
    global call_count
    call_count += 1

    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

fibonacci(10)
print(f"Call count: {call_count}")  # 看看调用了多少次


🎯 问题解决框架

框架:5W1H

遇到问题时,问自己:

问题 说明
What 什么现象?报错信息是什么?
When 什么时候发生的?
Where 在哪行代码?哪个函数?
Why 为什么会这样?
Who 哪个数据/变量导致的?
How 如何修复?如何预防?

示例应用

Text Only
问题:程序崩溃

What: IndexError: list index out of range
When: 运行到第15行时
Where: get_user函数
Why: 用户列表为空,但代码假设至少有一个用户
Who: users变量是空列表
How: 添加空列表检查

✅ 阶段检查

完成以下检查,确认你掌握了调试能力:

  • 能读懂Python错误信息
  • 能用print定位问题
  • 能用断点调试
  • 能写出最小复现代码
  • 能独立修复常见bug
  • 能预防常见错误

📚 下一步

完成调试能力训练后,进入 04-阅读源码技巧.md


记住:调试能力决定了一个程序员的上限。掌握调试,你就掌握了编程! 🔧