资讯详情

资讯详情

吃透Python第十章:五类课后习题考点与六大易错陷阱全解析

前几天有位同学抱着《Python程序设计与算法基础教程第二版》来找我说前面九章的课后题自己都能做偏偏卡在第十章。我一开始也以为这一章只是多讲了些新语法翻完题才发现第十章几乎每一道题都在逼你把前面学过的所有东西串起来用。程序阅读要看懂函数嵌套改错题要同时检查缩进和数据类型编程题动不动就是文件读取加字典统计加排序输出任何一个环节掉链子整个程序就跑不起来。我陪他把第十章课后习题重新过了一遍又把手头的错题整理成了笔记。这篇不是简单把答案贴出来让你抄而是把每类题目背后的考点、容易踩的坑、以及能直接复现的参考代码都讲清楚。刷题归刷题真要提升水平还是得弄明白“为什么这么写”。下面这些内容是给想把这章彻底吃透的人准备的。1. 第十章卡住的真正原因从单点语法到综合运用的转换1.1 这章不再考“某一个功能”而是考“功能的组合”如果你按顺序刷这本书会发现前面九章的习题目标很明确练习列表就只操作列表练习循环就只写循环练习函数就只传参数返回结果。到了第十章题目风格突然变了。以我手里这本教材为例第十章开始把异常处理、文件操作、自定义函数、类与对象、常用算法这些内容混合在同一个题目里出现。说得直白一点前三章像在练“单关节动作”第十章突然变成“组合动作”。比如一道统计词频的题你需要先打开文件这个环节要处理文件不存在的情况然后要处理标点符号这里要用到字符串方法或正则接着要用字典统计出现次数隐含条件是键不存在时的初始化最后还要按次数排序输出。四个步骤环环相扣哪个环节的思路不清晰都不行。在做课后题之前我建议你先复习一下下面这张知识承接表。别小看这一步很多同学做不出题不是不会写代码而是前面某块内容已经模糊了到第十章才暴露出来。前面章节的知识点第十章习题中的常见用法if/else 分支判断文件是否存在、判断键是否在字典中、处理边界条件for/while 循环遍历文件的每一行、遍历字典的键值对、循环填充列表列表与字典临时存储、计数统计、排序后的结果组织函数定义与返回把一段完整逻辑封装成函数便于测试和复用字符串操作清理标点、大小写转换、按空格拆分成单词异常处理文件读取失败、转换时出现格式错误、用户输入非法数据1.2 课后习题的常见类型与应对策略不同印次的教材第十章具体的章节主题可能有调整但习题类型基本固定大致可以分成五类。这五类题目的应对逻辑完全不同搞清楚类型比埋头苦写更重要。第一类是选择题通常考察语法细节。比如某个函数参数是列表还是元组、某个方法改的是原对象还是返回来一个新对象。这类题不需要真跑代码靠准确记忆就能解决。我一般让学生把“原地修改”和“返回新对象”的操作分开记这个分类如果混乱选择题几乎必错。第二类是程序阅读题给出一段代码让你推演输出结果。这种题考察的是“人肉执行代码”的能力关键是要把每一步的变量变化理清楚我后面会专门讲一个三步推演法。第三类是程序填空题题目把完整的代码挖掉几个空让你补上关键表达式。这类题考的是对API的熟悉程度本质上没什么技巧练多了自然知道空里该填的是什么。第四类是程序改错题这是考试最常见的丢分点。改错题通常有两种思路一是看语法二是看逻辑。语法错误包括缩进不对、变量拼写不一致、函数调用时参数数量不对逻辑错误更隐蔽比如边界条件少处理了一个、循环范围多循环了一次。后面我会把高频出现的六个陷阱单独列出来讲。第五类就是编程题也是最花时间的一类。我的建议是不要一上来就想一次写对先画流程再写代码最后用测试数据验证。这个过程和我们写真实项目的思路很像纯靠背答案解决不了问题。2. 程序阅读与选择题三步推演法不靠背答案2.1 第一步标注变量变化的关键节点程序阅读题不是“看一眼就猜答案”得分的前提是把代码在脑海里运行一遍。我的习惯是先把代码里所有变量名标出来重点看哪些变量在循环里被反复覆盖哪些变量是累积型变量。累积型变量通常是突破口比如统计总数的 total、拼接字符串的 result、记录次数的字典等。举一个典型例题题目问下面这段代码的输出是什么def demo(n): result [] for i in range(n): if i % 2 0: result.append(i * i) else: result.append(i 1) return result print(demo(5))很多同学会直接猜 [0, 1, 4, 9, 16]因为他们下意识以为所有数字都按平方处理了。但如果按照变量变化来看i 分别为 0、1、2、3、4 时偶数走平方分支奇数走加一分支。所以实际结果是 [0, 2, 4, 4, 16]其中 i1 时得到 2i3 时得到 4。2.2 第二步按执行顺序在手边画一张“状态表”遇到稍微复杂点的程序阅读题心算很容易出错。我的建议是直接在本子上画状态表横轴写步骤序号竖轴写关键变量。每执行一行代码就更新一行状态。看起来笨实际上是最稳的方法。比如看下面这段data [3, 1, 2] new_data [] for x in data: new_data.append(x * 2)你画表时只需要记录 three 个内容当前取到的 x 是多少、new_data 此刻是什么、data 有没有被更改。画完之后就会发现data 从头到尾都是 [3, 1, 2]而 new_data 逐渐变成 [6, 2, 4]。绝大多数程序阅读题只要把状态表画完整答案就自己冒出来了。2.3 第三步复查循环边界和返回值推演出结果之后别急着选答案。最后一步一定要检查循环边界。Python 的 range(n) 表示 0 到 n-1很多同学推演到一半默认它包含 n导致结果差一个数。另外函数题重点看 return 的位置。return 如果放在循环内部那么函数第一次循环就会结束后面的操作都不会执行如果放在循环外部就会等整个循环跑完才返回。这个差别在选择题里特别喜欢考我见过太多次因为没注意 return 缩进位置而丢分的例子。选择类题目还有一种高频考点函数参数是“值传递”还是“引用传递”的变体问题。比如向列表里 append 整数外部列表会被修改但如果重新给变量赋一个全新的列表外部列表不受影响。遇到这种题先看代码里是“修改对象内部”还是“重新赋值对象变量”判断会清晰很多。3. 改错和填空中最常出现的六个坑我逐个排给你看3.1 缩进不一致看起来是逻辑错误其实是语法错误缩进在 Python 里是语法的一部分。改错题里最常见的失败方式是缩进混用空格和 Tab。你用文本编辑器看可能觉得没问题但解释器会报 IndentationError或者更麻烦的是不报错但执行结果不对。因为 Python 会把不同层级缩进的代码块当成完全不同的逻辑块。检查方法其实很简单把编辑器里的“显示空白字符”打开所有缩进统一用四个空格。如果真的在考试环境里无法设置那就把所有 Tab 全部替换成空格再检查一遍。这步做完至少能排除三分之一的人为错误。3.2 可变对象作为函数默认参数这个坑不报错但结果诡异改错题特别喜欢考察这个点。下面这段代码看起来完全正常但运行结果会让新手懵住def add_item(item, items[]): items.append(item) return items print(add_item(1)) print(add_item(2))第一次调用输出 [1] 是预期中的第二次调用很多人以为输出 [2]实际输出却是 [1, 2]。原因是 Python 的函数默认参数在定义时只计算一次默认列表在整个程序运行期间被反复使用第二次调用时原来的列表还没被清空。正确写法是用 None 占位def add_item(item, itemsNone): if items is None: items [] items.append(item) return items这个知识点在填空题里也很常见空位上要填的是 None而不是 [ ]。如果题目让你“修改一个默认参数为列表的函数”十有八九就是在考这个坑。3.3 异常捕获的顺序不对子类异常永远到不了第十章如果涉及异常处理改错题里有另一种高频错误捕获类型的顺序写反了。比如你需要同时处理 FileNotFoundError 和 Exception如果把 Exception 写在前面那么 FileNotFoundError 这个更具体的异常就永远没有机会被捕获。这就像你准备了两张网一张粗网在前一张细网在后细网里可以接住的鱼全被粗网拦掉了。正确的顺序一定是先写具体的异常再写通用的异常。每次写完异常处理我都习惯在心里问一句这里有没有更庞大的异常类被提前捕获了如果有就调整顺序。3.4 文件读取后没有关闭程序不报错但资源一直被占着很多同学课后题能写出来但文件相关的代码总是差一口气。典型错误是不用 with 语句直接 open 后忘记 close。在小型习题里这个问题不会立刻报错程序也能正常输出所以很多人不知道自己的写法有问题。如果题目要求你写一个能反复读取文件的函数文件句柄没有关闭第二次调用时可能会读到已经被占用的文件。我在做这类改错题时会优先把 open 改成 with open这样在代码块退出时会自动关闭文件。如果题目明确要求使用 try-except那就在 finally 里关闭文件。永远不要在文件操作里偷懒。3.5 原地修改和返回新对象混淆列表操作最容易被混起来列表的 sort、append、extend、remove 都是原地修改返回的是 None而 sorted、拼接后加号、切片操作返回的是新对象。改错题里最常见的问题是data [3, 1, 2] data data.append(0)这段代码执行完之后data 变成了 None因为 append 在原地修改了原列表然后返回 None你把这个 None 又赋给了 data。正确写法应该是直接 data.append(0)不需要再赋值。这种错误在程序阅读题里也很喜欢考答题时遇到返回值赋值的语句先查一遍方法到底返回什么。3.6 递归缺少出口不报语法错但运行到最大值才崩如果第十章内容涉及递归或算法那缺少递归出口是最典型的错误。比如二分查找、阶乘、斐波那契数列递归函数里如果没有明确写出递归结束条件解释器会一直递归下去直到触发 RecursionError。填空题里经常给出递归函数的主体让你补一个空这个空往往就是结束条件。检查的时候只需要把递归参数代入“达到某种边界时该返回什么”这个问题答案就明确了。比如阶乘函数里参数为 0 或 1 时返回 1这个分支就是要补的位置。4. 编程题参考代码两道高频综合题从题目到跑通的完整拆解4.1 文本词频统计题文件、字符串、字典、排序全部用上这是第十章非常经典的一道编程题题目一般会这样描述读取一个文本文件统计其中每个单词出现的次数并输出出现频率最高的前十个单词。这道题几乎就是第十章知识点的集大成者我把参考代码写了出来配合说明逐段理解。import re from collections import Counter def word_frequency(filepath, top_n10): try: with open(filepath, r, encodingutf-8) as f: text f.read() except FileNotFoundError: print(文件不存在请检查路径) return [] words re.findall(r[a-zA-Z0-9\u4e00-\u9fa5], text.lower()) counter Counter(words) return counter.most_common(top_n) if __name__ __main__: result word_frequency(sample.txt, 10) for word, count in result: print(f{word}: {count})第一段用 try-except 包住文件读取捕获文件不存在的情况。这里 with open 就是前面提到的最佳实践代码块结束文件自动关闭。接着用 re.findall 提取字母、数字和中文组成的单词text.lower() 先把所有字母变成小写避免不同大小写被当成两个词。Counter 来自 collections 模块它一次性完成计数再用 most_common 按频率从高到低输出前十个单词。如果你手头没有现成的文本文件可以在代码同目录下建一个 sample.txt随便写几行英文或中文。用这段代码跑一下能顺利输出前十个高频词然后就可以拿这份代码作为模板去套课本上同类型的其他题目了。4.2 迷你图书管理类设计题类、异常、列表操作综合应用第十章如果偏向面向对象内容常见的编程题目就是让你定义类比如图书类、学生类、账户类。我拿图书管理来举例因为它涉及的属性、方法、异常逻辑都比较典型。class Book: def __init__(self, title, author, year): self.title title self.author author self.year year self.is_borrowed False def borrow(self): if self.is_borrowed: raise ValueError(这本书已被借出) self.is_borrowed True def return_book(self): if not self.is_borrowed: raise ValueError(这本书没有被借出) self.is_borrowed False def __str__(self): status 已借出 if self.is_borrowed else 可借 return f《{self.title}》 {self.author} {self.year} {status} books [] books.append(Book(Python入门, 张三, 2022)) books.append(Book(算法详解, 李四, 2021)) try: books[0].borrow() print(books[0]) except ValueError as e: print(e)这段代码的关键点有三处。第一类属性 is_borrowed 用布尔值表示借阅状态borrow 和 return_book 方法都在状态不正确时主动抛出 ValueError而不是让程序静默出错。第二books 这个列表承担了数据管理的角色模拟了真实项目中的对象容器。第三str方法决定了 print(对象) 时显示什么内容方便调试。学生写这类题时最容易忽略的是状态验证。简单版只写 self.is_borrowed True没有判断当前状态逻辑上是有缺陷的。借用这道题的思路遇到类似的类设计题一定要考虑方法在非法状态下怎么做这属于“防御性编程”的入门训练。4.3 从报错到跑通的调试顺序先验证输入再跟踪输出写完编程题不要急着说“我做完了”。我带的同学里十个人有九个写完就交结果一跑就报错。我会要求他们按照下面这个顺序来自检。第一步先跑空输入和边界输入。比如词频统计函数可以试试文件存在但内容为空的情况这个结果应该返回一个空列表而不是报错。第二步在关键位置加 print 输出中间变量比如统计词频前先输出提取到的 words 的前二十项看看标点符号是否清理干净、中文英文是否被正确拆分。第三步把函数的输出跟手算结果对照用只有两三个单词的测试文本人工算一遍对比程序输出是否一致。这套调试思路在真实开发里也通用。很多人遇到程序报错就慌了其实大部分问题可以通过“查看中间数据”找到根源。不要在没有任何输出的情况下瞎改代码先舍得加 print跑通之后再删掉或者改成日志。5. 刷完第十章习题之后我建议你再做三件小事5.1 按“知识点”而不是“题号”整理错题很多同学做课后题喜欢对答案、改分数、然后翻页过两周再遇到同类题还是错。更好的做法是按知识点归错题。比如把“默认参数是可变对象”“忘记关闭文件”“异常顺序写反”这三类问题放在一起哪怕题号隔得很远本质上都是同一类坑。我自己整理错题时会画一个简单的表格错题编号、涉及的知识点、错误代码片段、正确写法、错误原因。重点不在于写得多工整而在于记录“为什么当时会写错”。这个原因比标准答案重要得多它会直接告诉你思维盲区在哪里。5.2 把有代表性的习题代码改成通用模板做课后题的目的是把知识转化成可复用的能力。每道题做完之后想一想这段代码的核心逻辑能不能在别处用。比如词频统计的例子稍微改一下正则表达式就能用来统计日志文件里某个错误类型出现的次数图书管理类的结构换成商品类、订单类照样可以运行。我会把这类代码整理成一个模板文件每个函数只做一件小事参数尽量通用。以后再遇到第十章同类型的编程题就直接调用模板改两行而不是从头敲到尾。这种做法和工作中常用的“工具函数”思路一致现在养成这个习惯后面写项目时会轻松很多。5.3 每道题都用“边界测试”过一遍再收工能跑通用例并输出结果只是基础离真正的做对还有差距。我建议你在提交之前有意识地问自己几个问题如果输入是空列表怎么办如果文件不存在怎么办如果用户输入的是负数怎么办如果字符串里包含大量标点符号怎么办这些问题就是编程里的“边界情况”。课后题的标准答案往往只覆盖了正常情况但真正的能力差距往往体现在边界处理上。考试时老师也特别爱在边界上设计扣分点因为正常路径大家都会写只有边界能区分水平。我现在每次带学生刷完一章都会让他们把每道编程题的边界测试结果截图保存下来。看起来是麻烦一点但这个习惯对建立代码信心特别有帮助当你知道这段代码在极端情况下也不会崩心里才真正有底。这大概也是刷课后题从“会做”到“做扎实”最关键的一步。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →