学径 LearnPath

CAICP-E · Python 编程基础 / Wiki

调试

找出程序为什么不对,再把它修好。

它是什么

调试 就是找错和改错。 程序出错时会说话。 先看最后一行的错误名字。 再看它指出的行号。

调试不是惩罚。 它更像体检:哪里红肿,就去哪里看。 会调试的人,不是从不犯错的人,而是能把错找出来的人。

程序也许能跑,结果却不对。 那也要调试。 这时没有红红的报错,要对着 算法 步骤,一行行走。

名字从哪来

debug 的意思是「去掉虫子」。 bug 在英语里是虫子,也用来指故障。

1947 年 9 月 9 日,哈佛大学的 Mark II 计算机出了故障。 工作人员在继电器里发现一只被夹住的飞蛾,把它贴进了日志本。 旁边写着:第一次真正找到虫子(First actual case of bug being found)。 格蕾丝·霍珀(Grace Hopper)的团队把这个故事传开了。 那本贴着飞蛾的日志,后来收藏在美国史密森尼博物馆。

「故障叫 bug」其实更早就有人用。 霍珀他们让这个词在计算机世界里出了名。

还有一个有名的办法叫橡皮鸭调试法(rubber duck debugging)。 1999 年的书《程序员修炼之道》讲过:有人把一只小黄鸭放在桌上,把自己的程序一行行讲给鸭子听。 讲着讲着,自己就听见哪里说不通了。 鸭子不会写代码。 它只是逼你把步骤说清楚。

它怎么工作

常见报错

  • SyntaxError:语法错。常忘冒号、括号或引号不配对。
  • IndentationError缩进 不对。
  • NameError:名字还没定义。
  • TypeError:类型不匹配。例如文字加整数。
  • IndexError列表 下标超出范围。
  • ValueError转换 失败。例如 int("hello")
python
for n in range(3)   # 少了冒号,SyntaxError
    print(n)
python
print(score)  # 还没赋值,NameError
python
print(3 + "2")  # TypeError

修 bug 的步骤

  1. 读报错最后一行
  2. 看行号
  3. 对照 注释 想本来要做什么
  4. 改一处,再运行一次

不要一次改十处。 改太多会迷路。

可以插入 print,把盒子里的值显示出来。 看见实际是什么,才知道和想象差在哪。

补全残缺代码时,先读注释。 注释写了目标,就按目标填。 保持 4 空格缩进。 名字用小写加下划线。

例如顺序查找缺一行「找到就停」。 最合适的常常是 break,不是 continue,也不是 pass

pass 什么也不做。 continue 只跳过本圈。 return 用在 函数 里送结果。

讲给橡皮鸭听,也是合法步骤。 没有鸭子,讲给铅笔、讲给同学、讲给自己听,同样有效。

生活里在哪里

  • 作业算错:从最后一步往回看,哪一行开始不对。
  • 乐高缺一块:对照说明书,找到漏装的那一步。
  • 灯不亮:先看插头,再看开关,一次查一处。
  • 作文病句:老师圈出行号,你对那一行改。
  • 迷路:回到上一个路牌,而不是随便再走十个路口。

科学家做实验失败,也会查步骤。 调试是同一种态度:证据,而不是碰运气。

和相近概念的差别

报错是信号。 调试是读信号、做修改的过程。

算法错了,程序可能完全不报错。 那叫逻辑错误。 语法错误通常跑都跑不起来。

注释 帮助调试,因为它写下了「本来要干什么」。 目标和实际一对照,错处会跳出来。

测试是先准备例子,看结果对不对。 调试是已经发现不对,去找原因。 先有例子,调试才有靶子。

常见误会

误会 1:报错就是失败。

报错更像老师批改。 它在帮你指出行号和类型。

误会 2:只看第一行英文,不看最后一行类型。

真正的错误名字,常常在最后一行。

误会 3:乱加引号或括号「碰运气」。

一次改一处。 改完立刻再跑。

误会 4:缩进用眼睛估。

按 4 的倍数对齐。 混用空格和 Tab 会更难查。

误会 5:能跑就一定对。

结果还要用人的标准检查。 尤其是 查找 和枚举,边界最容易悄悄出错。

想知道更多

  • 书:潘洪波《小学生 Python 趣味编程》、埃里克·马瑟斯《Python 编程:从入门到实践》里的练习,做不出来时正好练「读报错、改一处」。
  • 电影:《隐藏人物》(Hidden Figures)。和家长一起看:算错了怎样回头检查步骤——那正是调试的态度。

未登录时不会保存学习进度