Skip to content

第 12 章 阅读 AI 生成的代码

学习目标

  • 掌握阅读代码的顺序:先签名,后结构,再验证
  • 会用边界测试发现 AI 代码里的隐藏 bug
  • 会按审查清单评估并改进 AI 生成的代码
  • 树立「理解并验证后再使用」的态度

12.1 为什么要专门练「读 AI 代码」

本书的核心理念之一:学完后,你既要能独立写 Python,也要能读懂 AI 生成的 Python 代码。AI 生成的代码通常能运行,但可能有三类问题:

  1. 隐藏 bug:常规输入正常,特殊输入出错。
  2. 命名随意:变量叫 tsx,读起来费劲。
  3. 写法冗长或脆弱:能跑,但容易在边界条件下崩溃。

本章教一套固定的阅读流程,让「读 AI 代码」从凭感觉变成有方法。

12.2 阅读顺序:签名 → 结构 → 验证

第一步,看签名。 函数名、参数、返回值,先猜它的意图:

python
def find_max(nums):
    max_num = 0
    for n in nums:
        if n > max_num:
            max_num = n
    return max_num

find_max(nums) —— 名字说明「找出列表里的最大值」,参数是列表,返回一个值。意图明确。

第二步,看结构。 顺着数据流读:nums 里的每个 n 依次与 max_num 比较,大的赋值给 max_num。逻辑上「维护当前最大值」的思路是对的。

第三步,验证。 光看不行,必须运行,尤其要测边界条件:

python
print(find_max([3, 1, 2]))     # 常规:3
print(find_max([-5, -1]))      # 全负数:?

输出:

3
0

bug 出现了:find_max([-5, -1]) 返回 0。原因:最大值初始化为 0,而列表里全是负数,0 比谁都大。常规输入一切正常,边界输入暴露了问题——这正是 AI 代码最常见的 bug 类型。

12.3 边界测试

边界条件指容易出错的特殊输入:空列表、全负数、最大值在开头/结尾、重复元素、超大数等。测试时把常规值和边界值都跑一遍。

修复 find_max:不预设初始值,改用「第一个元素」或直接调用内置函数:

python
def find_max(nums):
    if not nums:            # 空列表返回 None
        return None
    return max(nums)

print(find_max([3, 1, 2]))
print(find_max([-5, -1]))
print(find_max([]))

输出:

3
-1
None

修复的同时处理了第二个边界:空列表。原代码对空列表会报 ValueError: max() arg is an empty sequenceUnboundLocalError,新版本显式返回 None

12.4 审查清单

阅读和改进 AI 代码时,逐条检查:

  1. 边界处理:空输入、负数、0、超长输入会不会崩?
  2. 命名清晰:变量名是否能表达含义(nums 优于 s,total 优于 t)?
  3. 异常处理:可能出错的输入(用户输入、文件读取)有没有 try/except?
  4. 重复代码:同样的逻辑是否出现多次?能否提取成函数?
  5. 复杂度:有没有不必要的循环或嵌套?能否用内置函数(如 summax)简化?

12.5 实例:改进一个能跑但脆弱的代码

假设 AI 生成下面的平均分函数,常规输入没问题:

python
def average(grades):
    total = 0
    for g in grades:
        total = total + g
    return total / len(grades)

print(average([85, 92, 78, 90, 66]))

输出:

82.2

按清单检查:

  • 边界:average([]) 会怎样?len(grades) 为 0,除数为 0,抛 ZeroDivisionError。空列表是真实的输入场景,必须处理。
  • 简化:循环累加等价于 sum(grades),可读性更好。

改进:

python
def average(grades):
    if not grades:
        return 0
    return sum(grades) / len(grades)

print(average([85, 92, 78, 90, 66]))
print(average([]))

输出:

82.2
0

12.6 实例:让代码更简洁

AI 生成的这段代码功能正确,但写法啰嗦:

python
def count_words(text):
    words = text.split()
    result = {}
    for word in words:
        if word not in result:
            result[word] = 1
        else:
            result[word] = result[word] + 1
    return result

利用字典的 get(key, 默认值),可以把「不存在则从 0 开始」合并成一行:

python
def count_words(text):
    result = {}
    for word in text.split():
        result[word] = result.get(word, 0) + 1
    return result

print(count_words("a b a"))

输出:

{'a': 2, 'b': 1}

两种写法结果完全一致,后者更短、意图更清楚。读 AI 代码时,「能跑」是底线,「好读、好维护」是目标。

动手实践

任务一:解读并修复。 下面的 AI 代码目标是把列表里所有数字相加。运行常规输入和空列表,按审查清单找出问题并修复:

python
def total(nums):
    t = 0
    for i in nums:
        t += i
    return t

任务二:边界测试。 对下面的 AI 代码,写出至少 4 组测试输入(含边界),运行并记录结果,判断它是否有 bug:

python
def first_half(text):
    return text[:len(text) // 2]

提示:考虑空字符串、长度是奇数、长度是偶数、长度是 1。

任务三:改写。summax 重写「求列表最大值和总和」的函数,并处理空列表。

常见错误

错误做法说明
复制粘贴 AI 代码直接上线未经边界测试,隐藏 bug 会在真实数据上爆发
只测常规输入find_max([-5, -1]) 这类边界输入最能暴露问题
看不懂也照用出问题后无法定位;坚持「先读懂再使用」
认为能运行=正确正确性要靠边界测试和人工审查,不只是「没报错」
AI 给的 API 直接照抄函数签名、参数可能并不存在,运行时才暴露 NameError

章末练习

基础

  1. 简述阅读 AI 代码的三个步骤。
  2. 写出 find_max([-5, -1]) 在原版(初始化为 0)代码下的结果,并解释原因。
  3. 解释 result.get(word, 0) + 1 这行代码的含义。

提高

  1. 下面的 AI 代码有什么问题?修复它:
    python
    def divide(a, b):
        return a / b
  2. 写出对 first_half 的 4 组测试输入及对应正确结果,再运行验证。

挑战

  1. 下面 AI 代码的目标是「返回列表里第二大的数」。用边界测试找出 bug 并修复:
    python
    def second_largest(nums):
        nums.sort()
        return nums[-2]
    提示:考虑列表长度不足 2、有重复元素的情况。
  2. 选一段自己或 AI 写的 20 行以内的代码,按 12.4 审查清单逐条检查,写一份简短的审查报告(每条清单:通过 / 不通过 + 说明)。

章末自测

每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。

  1. 阅读代码的第一步通常是?
    • A. 逐行读全部代码
    • B. 先看函数签名与意图
    • C. 直接改代码
    • D. 删除注释
  2. 边界条件不包括?
    • A. 空列表
    • B. 全负数
    • C. 常规正整数
    • D. 超长输入
  3. 原版 find_max(初始值 0)对 [-5, -1] 返回?
    • A. -1
    • B. -5
    • C. 0
    • D. 报错
  4. average([]) 在原版代码下会?
    • A. 返回 0
    • B. 报 ZeroDivisionError
    • C. 返回 None
    • D. 返回空
  5. result.get(word, 0) 在键不存在时返回?
    • A. 报错
    • B. 0
    • C. None
    • D. word
  6. 判断 AI 代码是否正确,最可靠的方法是?
    • A. 读一遍
    • B. 运行并测试边界
    • C. 问其他人
    • D. 看代码长度
  7. 审查清单中「重复代码」一项关注的是?
    • A. 代码行数多少
    • B. 同样的逻辑是否出现多次
    • C. 注释多少
    • D. 变量类型
  8. 空列表传给 sum([]) / len([]) 会?
    • A. 返回 0
    • B. 报 ZeroDivisionError
    • C. 返回 None
    • D. 返回空列表
  9. 对 AI 代码的正确态度是?
    • A. 一律不用
    • B. 理解并验证后再使用
    • C. 直接使用并信任
    • D. 只用于学习
  10. max([]) 会? A. 返回 0 B. 返回 None C. 报 ValueError D. 返回空