简介:COMP9021课程Python编程练习与测验资料合集是悉尼新南威尔士大学Principles of Programming课程的配套练习包,覆盖Python基础语法、控制流、函数定义与简单数据结构应用,适合课堂同步巩固、课后自主复习与考前冲刺。压缩包共7个文件,包含quiz_1.py源代码、quiz_1.pdf和quiz_2.pdf两份测验文档,以及配置文件、HTML说明页等,整体仅54KB,目录结构清晰,可在IDLE、VS Code等IDE中直接加载运行。目前已有15人学习/下载。quiz_1.py内含多个带详细注释的函数,覆盖变量类型推断、数值与字符串运算、布尔逻辑、输入输出等要点;quiz_1.pdf含单选、多选、填空、简答题并配有答案解析,便于定位常见易错点。quiz_2.pdf难度进阶,重点考察函数参数传递、作用域、递归以及列表、元组、字典的应用,并提供逆向分析题,可系统检验对Python语言本质的理解与工程实现能力。
1. 从测验倒推的 Python 课程练习:这份 COMP9021 合集到底在解决什么问题
如果你正为 Python 编程课程测验焦虑,或者身边攒了不少编程练习资料却不知道从哪里看起,COMP9021 课程 Python 编程练习与测验资料合集的定位,恰恰是替你省掉整理和筛选的时间。它不是从头讲语法的教材,而是一套围绕课程测验反推整理的编程练习与测验题库合集:内容包括按知识点拆分的练习、测验真题样例、参考实现,以及每道题对应的关键注释。它不打算把基础概念重新讲一遍,而是用反复出现的题型告诉你课程真正考什么——数据处理、边界条件、异常处理、类与继承在限定时间内的熟练度。适合两类人:一类是课程进行到一半、希望提前进入考试状态的在校学生,另一类是打算转 Python 开发、需要一个现成自测清单的在职从业者。通过它,你能快速识别自己哪些地方会,哪些只是“看上去会”。
2. 合集内容抽查:一套按测验结果反推出来的四个模块
2.1 从练习题到测验题的粒度差异:先看资料里的题型层
我拿到这类课程资料后的习惯,不是从第一页开始看,而是先翻目录,找“题型分类”。这套合集一般会按四个纬度组织:语法单项练习、综合编程题、选择题/改错题、往年测验套题。语法单项练习往往只有十余行代码规模,覆盖基础语法、数据结构、文件读写;综合编程题则更像一个小型功能模块,需要在限定时间内完成输入解析、逻辑处理和输出格式化;选择题与改错题则用来填补脑内“概念盲区”。
这套 COMP9021 课程资料最有价值的部分,是它对测验题型的颗粒度拆分。同样是“考递归”,练习版本通常给出明确的递推公式,比如“计算 Fibonacci 数列并输出前十项”;但测验版本会换成“判断一个嵌套列表中的最大深度”,没有提示要用递归,也没有模板。解法是否能在默写层面写出来,就取决于你平时练习时是否做过“从题目反推知识点”的拆题训练。
大部分编程练习资料只有一个参考答案,看懂的当下觉得很简单,自己写的时候却卡在循环不变量、变量作用域和边界条件上。所以我在使用这套资源时会给它加一道工序:每一道题都先当成测验来做,不看参考实现,限时完成,再把自己的答案和参考答案对照。资料里的注释一般写得比较长,因为它面向新手,逐行解释了什么变量为什么存在、为什么先做空值判断。这不是替你做决定,而是帮你在对照时看清自己的判断路径。
2.2 测验样例的作用边界:不是用来背题的,是用来做回归的
很多学生会把测验真题样例当作“背题材料”,但我的建议是反着用。背题只能应对原题,课程测验最常做的是“同知识点换个壳”。举个例子,资料里若出现“给定一个字符串,统计每个字符出现的次数并输出到字典”,你背下这题的答案,下一次它换成“给定一个列表,统计每个元素出现次数并输出由大到小排序的结果”,你就需要知道排序部分应该怎么修改。因此,测验样例的正确打开方式是当作“回归测试集”:先用这道题验证自己的函数能通过所有预期输出,再自己修改几个输入,看看逻辑是否仍然稳定。
这套 COMP9021 课程资料里常见的做法是:每道综合题后附上 2 到 3 组输入输出样例,并把最终输出结果贴在题目下方。为了不被样例限制住,我在复现时甚至会故意构造非法输入,比如空字符串、负数、超长字符,看自己的实现能不能妥善处理。如果参考答案直接没有处理这些边界,那你在照抄之前就要想清楚:测验的判题环境里是否包含隐藏测试用例。在一个严格评测系统里,答案一旦遇到异常输入就会直接判 0 分,而不是按“核心逻辑正确”给部分分数。
针对不同的人,资料的使用侧重也不同。如果你刚走到文件操作和异常处理这一阶段,建议只挑其中的“语法单项练习”部分做限时训练;如果你已经进入复习阶段,就把“往年测验套题”当作全真模拟,按时间要求一次做完一整卷。最忌讳的是把所有题目混在一起做,这样既看不出自己的薄弱点在哪个章节,也练不出考场上的时间分配能力。
3. 单题拆解演示:以字符统计这道高频测验题为例
3.1 为什么先拿字符串处理题热身:输出可预测,反馈最直接
字符串处理是 Python 课程测验里出现频率最高的一类题目。原因有三:第一,输入输出格式清晰,适合机器判题;第二,字符串方法丰富,可以考察对内置函数的熟悉程度;第三,它天然包含边界条件,比如空字符串、大小写混排、中英文混排。你不需要依赖任何第三方库,只用 Python 内置模块就能完成。这使得它成为验证“自己是否真的会写代码”的最低成本测试。
常见做法是要求写一个函数 count_chars(s),输入一个字符串,返回一个字典,键为字符,值为该字符出现的次数。表面看只是遍历一遍然后计数,但测验中常见的变体是要求“忽略大小写”“忽略空白字符”“最后按出现次数从大到小输出”。如果你只背了最简单的版本,遇到变体就会卡壳。正确的拆解方式是把需求拆成三步:预处理输入、统计频次、排序输出。任何变体都只是在这三个环节之一做替换。
3.2 一个带边界判断的字符频次统计实现
def count_chars(s: str, ignore_case: bool = False, ignore_whitespace: bool = True) -> dict: """ 统计字符出现次数,支持忽略大小写和空白。 返回字典 key: 单个字符, value: 出现次数 """ # 1. 预处理:统一大小写(可选) if ignore_case: s = s.upper() # 2. 预处理:移除空白字符 if ignore_whitespace: s = ''.join(ch for ch in s if not ch.isspace()) # 3. 边界条件:空字符串直接返回空字典 if not s: return {} freq = {} for ch in s: # 这里用 get 而不是先做 if 判断,代码更短且不会丢计数 freq[ch] = freq.get(ch, 0) + 1 return freq result = count_chars("Hello, World! ") print(result)逻辑说明:第一步把 ignore_case 判断放在修改字符串之前,保证后续统计不会重复处理同一个字符;第二步用生成器过滤空白字符,生成一个新的字符串,避免在原字符串上多次遍历;第三步的空字符串判断放在统计之前,可以省掉一次多余的字典创建。主循环里使用 dict.get(key, 0) 来初始化计数:如果键不存在,插入键并设初值为 0,再加 1;如果键已存在,直接在当前值基础上加 1。
参数说明:ignore_case 为 True 时,字符被强制转换为大写,因此结果字典里不会出现同一个字符的大小写两个键;ignore_whitespace 为 True 时,空格、换行、制表符等会被过滤,这样输出结果更贴近“只统计有效字符”的题意。若你的测验题目要求保留空白字符,把它改为 False 即可。需要特别注意的是,Python 中字符串是不可变对象,对 s 的任何“就地修改”语法都不存在,所以这里必须通过重新赋值的方式完成大小写转换和过滤。
3.3 三种测验变体的应对套路
同一道统计题,在课程测验中至少会有三种变体。
第一种是“输出排序结果”。要求不只是统计次数,还要按出现次数从大到小输出字符,且次数相同的情况下按字符从小到大排序。此时你需要把字典转为列表,然后借助 sorted() 的 key 参数实现双重排序:
items = sorted(freq.items(), key=lambda item: (-item[1], item[0]))第二个参数 key 返回一个元组,负号让次数逆序,字符本身的正序作为次排序依据。常见错误是只写 key=item[1],结果在同一频率的字符输出顺序不稳定。
第二种是“指定只统计字母”。如果题目要求忽略数字和标点,你需要在过滤阶段同时判断 ch.isalpha()。这里要注意,isalpha() 会把中文、日文等字符也判定为字母,如果题库明确要求仅限 26 个英文字母,就需要额外检查 ch 是否在 ascii_letters 范围内。
第三种是“不区分大小写但输出保留原样”。例如输入 “Apple apple”,忽略大小写统计结果为 a:2, p:4, l:2, e:2,但输出的键不能全变成大写或小写,因为用户会较真格式。这时更稳妥的做法是靠两次遍历:第一次用小写形式检查是否出现过,第二次在原字符串上统计对应键。我一般会多保留一个 first_char 字典,记录每个小写键第一次出现时的原始字符,最后输出时用原始字符作为键。很多学生在这类变体上丢分,不是不知道怎么做,而是没考虑到“输出格式本身也是判分点”。
4. 用“本地验证器”把练习环境逼近课程测验评测机
4.1 写一个最简断言脚本:让练习不再依赖报错肉眼观察
很多同学做一个函数题,只看它没有报错就觉得通过了。但课程测验的判题逻辑远不止“不报错”这一条:它跑多组输入,每一组都检查返回值和预期值是否一致,哪怕只有一个字符不符合,也算该用例失败。
为避免这个坑,我给这套 COMP9021 课程资料的使用配了一个本地验证器。不需要学 pytest 这类外部框架,直接用 Python 内置的 assert 即可。常见做法是写一个 test_run() 函数,把题目附带的输入输出样例放进列表,循环调用被测函数:
def test_run(): test_cases = [ ("Hello, World!", {"H": 1, "e": 1, "l": 3, "o": 2, ",": 1, "W": 1, "r": 1, "d": 1, "!": 1}), ("", {}) ] for input_str, expected in test_cases: actual = count_chars(input_str, ignore_case=False, ignore_whitespace=False) assert actual == expected, f"输入 {input_str!r} 期望 {expected}, 实际 {actual}" print("全部可见样例通过")逻辑说明:断言失败会打印一条包含输入、期望值和实际值的错误消息,这样你可以直接定位是哪一组测试用例触发的问题。continue 和 break 在这里都不需要,因为 assert 一旦失败,程序立即停止,后续用例不会继续执行,这正是我们要的“快速暴露错误”的效果。该测试脚本完整跑完后,会输出“全部可见样例通过”。
参数说明:input_str 是原始输入字符串,expected 是手写期望输出的字典。手写期望值需要小心,这是环节最耗时的部分,但也是最值得的:你被迫把输出结果在脑子里推演一遍,而不是依赖参考代码帮你“猜”。我的习惯是每组测试用例后面加一行注释,说明这个用例覆盖了什么条件,比如“空字符串边界”“包含逗号和感叹号的特殊字符”“空格被过滤”之类。
4.2 给本地验证器补上隐藏用例生成器
在课程测验里,比样例更容易让人翻车的是隐藏用例。判题系统不会把隐藏用例展示给你,它只告诉你哪个用例失败,甚至不告诉你输入是什么。要想减少这种意外,最好的方式是自己生成一批“变态输入”,把能想到的边界都跑一遍。
生成输入不需要随机,需要的是结构性枚举:
def gen_edge_cases(): cases = [] # 空字符串 cases.append("") # 只有空白 cases.append(" ") # 大小写混合 cases.append("aAaA") # 重复字符只有一种 cases.append("ssss") # 数字与字母混排 cases.append("123abc123") # 超长字符串: 10000 个相同字符 cases.append("x" * 10000) # 包含换行与制表符 cases.append("a\tb\nc ") return cases for c in gen_edge_cases(): # 不设预期值, 只检查不抛异常且返回字典 result = count_chars(c) assert isinstance(result, dict), f"输入 {c!r} 返回类型错误"逻辑说明:这组用例覆盖了空输入、纯空白、大小写杂交、重复字符、数字与字母混合、超长输入以及控制字符几个典型类别。在这些用例上,肉眼看不到正确答案,但你可以从返回值结构上发现很多潜在问题:比如返回的字典键出现了不该存在的空字符串、报错信息提示超出递归深度、或者是处理超长字符串时性能明显卡住。assert isinstance 只是最低门槛,实际使用时我会在每个用例后接着打印 result,人工扫一眼是否有丢失字符。
参数说明:10000 个相同字符的用例,主要用来测性能极限。如果你的实现里用了嵌套循环而不是单层循环,这个字符串就会直接让程序卡顿几秒钟甚至更久,这在课程测验的限时里是致命的。换行与制表符的存在,则能检查你的过滤逻辑是否真的使用了 isspace() 而不是只判断空格字符 ' '。
4.3 用时间统计反推自己的熟练度
完成正确性验证后,还要记录耗时。同一道题,资料包里的参考答案可能十几行写完,你花半小时写出来,两者在课程测验里的收益完全不同。测验允许的时间通常只有几分钟,所以每次练习时我都会在脚本开头和结尾各记一次当前时间:
import time start = time.time() # 调用被测函数 result = count_chars("Hello, World!") end = time.time() print(f"耗时 {(end - start) * 1000:.1f} ms")逻辑说明:time.time() 返回自纪元开始的秒数,两次调用差值即为执行耗时,乘 1000 转成毫秒方便阅读。这样做不是为了精确做性能分析,而是要建立一个“耗时报警线”:比如你实现同样功能的代码在 100 个字符的输入上都要跑 50 毫秒,那么到 10 万字符时就会以平方级的速度恶化,这通常说明你使用了不必要的嵌套循环。
把练习时间刻意压缩到一半,人的大脑会被迫放弃“慢慢琢磨”的舒适节奏,改走最熟悉的语法路径。这也是我发现这套资料能带给使用者最大的改变:正确率只是及格线,而速度才是测验中的真正胜负手。每次限时训练后,我会把超过一分钟还没写出来的题目标记在题目旁边,作为第二轮的优先练习对象。
5. 课程测验避坑指南:五个让人怀疑人生的常见翻车点
5.1 现象:程序在自己电脑上输出正常,提交到评测系统后直接判 0 分
原因:最常见的情况是评测环境用的 Python 版本和你本地不一致,尤其是把 print 的默认分隔符、Unicode 字符串长度、round 的舍入行为当成固定不变的东西。另一个高频原因是你的代码读输入时用了 input() 处理全部数据,而评测系统是按行逐条喂给程序,导致第一次 input 只拿到第一行,后续逻辑直接错位。
解决:先在本地强制使用与评测环境一致的 Python 版本,搜索资料包里标注的运行环境。如果标注为 Python 3.8+,就永远不要用 Python 2 的 print 语法或 xrange。输入读取方面,我一般建议一次性读取全部标准输入再按行切分,而不是依赖多次调用 input():
import sys def read_all_lines(): return sys.stdin.read().splitlines()这样无论评测系统一次给一行还是多行,程序都能稳定拿到完整数据。它不改变逻辑结构,只是把“输入获取”和“逻辑处理”做了解耦,排查问题时也能更快定位是输入解析阶段还是算法阶段出错。
5.2 现象:参考答案能跑通所有样例,但你自己复现时字典顺序每次都不同
原因:Python 3.7 之前字典不保证键的顺序,3.7 之后虽然按插入顺序保持,但如果你对字典进行了多次增删操作,输出结果和参考实现会不一致。尤其是在使用集合推导式或字典推导式时,顺序受哈希影响,不同运行环境结果可能不同。
解决:凡是要求“按顺序输出”的题目,绝不依赖迭代字典本身。常见做法是把键取出来之后用 sorted() 显式排序:
for k in sorted(freq): print(k, freq[k])参数说明:sorted 默认按字符串的 Unicode 码点排序,对大写字母、小写字母混排的情况会得到 A 在 a 之前的顺序。如果题目要求按字母表不区分大小写排序,你需要写成 sorted(freq, key=str.lower)。这个坑在课程测验里的出现频率很高,因为参考资料很可能来自不同版本的解释器,你在本地复现时发现“输出顺序和答案不一致”,第一反应不应该是怀疑自己逻辑写错,而是检查排序规则。
5.3 现象:测试用例全部通过,但耗时几乎超时
原因:很多综合编程题会隐藏一个 10 万级数据量的用例,用来淘汰时间复杂度不达标的实现。常见写法是在循环内部反复调用 str.count、list.count 或 in 操作,这些操作本身都是线性扫描,嵌套后变成 O(n²),数据量一大就会卡死。
解决:把“重复计数”改成单次遍历。以统计词频为例,不要在每个字符上调用 s.count(ch),而应该用字典累积,只在主循环里对所有字符各访问一次:
freq = {} for ch in s: freq[ch] = freq.get(ch, 0) + 1这个版本的时间复杂度是 O(n),空间复杂度是 O(k),k 为不同字符数。如果你对性能没有把握,可以在本地生成一个 100 万字符的输入跑一遍,如果耗时超过一秒,就要考虑到评测机上可能多组用例叠加,从而进一步优化。
5.4 现象:函数第一次调用结果正确,第二次调用同一函数结果变得异常
原因:典型原因是函数内使用了可变对象作为默认参数,例如 def add_item(item, cache=[]): 默认参数只在函数定义时创建一次,后续所有调用共享同一个列表。第一次调用往里添加了元素,第二次调用还能看到第一次残留的数据。
解决:把可变对象默认值改成 None,在函数体内部再创建:
def add_item(item, cache=None): if cache is None: cache = [] cache.append(item) return cache逻辑说明:每次调用函数时,cache 都被重新初始化为一个新列表,不会跨调用保留状态。这是课程测验里比较隐蔽的坑,因为单测样例只调一次时看不出来,只有连续调用同一函数才会暴露。很多资料包的参考答案为了代码简短,可能会直接用可变默认参数,你在抄写之前一定要先判断它会不会在连续调用场景下出错。
5.5 现象:看到题目要求“输出每个元素出现的次数”,却漏掉了元素为负数的情况
原因:很多人在统计时使用数组下标作为计数索引,遇到负数或非整数元素就会抛出下标越界错误。这个问题在题目给定的样例里往往看不出来,因为样例通常只给正整数,但隐藏用例会包含负数,专门测试你的边界处理能力。
解决:统计类题目如果没有特别说明“输入均为正整数”,就不要默认输入范围等于列表下标范围。改用字典统计是安全的选择,因为字典的键可以接受任意不可变类型,负数、字符串、浮点数都不是问题。如果题目强制要求必须用数组,那就先对输入做一次偏移处理,把所有负数转到合法下标范围,并在代码注释里说明偏移量的设计依据。
6. 把练习改成答题工具箱:从“会做”到“随取随用”
6.1 给手边高频函数做一个小型代码片段库
当一套 COMP9021 课程资料里的练习被你按章节做完一遍后,再从头重做一遍的价值会递减。这时候我推荐换一个方向:把解题中写过的通用逻辑抽出来,组成自己专属的实用代码片段库。
这不是整理笔记,而是建立一个“随取随用”的函数集合。以字符串处理和统计类题目为例,常见函数包括:按空白拆分但保留引号内容、统计词频并按规则排序、清理 Unicode 中的不可见字符、把列表按指定步长切片。每一个都来自资料包中某一题的参考答案,但经过参数化改造后,可以被其他题目复用。
def split_keep_quotes(text): """ 按空白拆分字符串, 但保留引号内的内容不被拆分。 参数: text 原始字符串 返回: 拆分后的子串列表 """ import re return re.findall(r'"[^"]*"|\S+', text)逻辑说明:这段代码用正则把“带引号的内容”和“普通非空白字符串”都匹配出来。re.findall 返回所有匹配项,顺序和原文一致。它解决的问题是:统计一行参数时,空格分隔会导致带空格的参数被拆成两段,这在“命令行解析类”练习里特别常见。把它作为工具箱的一分子,下次遇到类似的输入解析题,你就不用从头写正则表达式。
参数说明:函数只处理英文双引号,如果课程测验要求支持单引号,把正则中的双引号换成 ['"] 即可。注需要注意,用单个正则同时匹配两种引号时,必须确保左右引号成对出现,否则会把残缺引号当作普通字符输出。
6.2 给自己建立一个“五步复盘”习惯
做完每一道练习,不管对错,我都会强制走一遍固定流程:看自己的输出和预期输出差在哪、想差距的原因、把错误原因归类到某一个知识点、把知识点对应的正确写法默写一遍、最后不看任何提示重新做一次。这套流程看起来笨,但确实把“看见了会做”变成了“下一次遇到同类题直接能写”。
从那以后,我每次使用课程资料合集,不管是练习包还是往年测验真题,都会提前把要做的题目范围限定在 30 分钟内,并在时间结束后立刻对照答案。如果发现自己在一个知识点上连续翻车两次,就把它记在一个单独的错题文件里,等整套资料刷完后再集中做针对性训练。这比漫无目的地从头看到尾有效得多。每个视频软件的新手往往都靠抄题和背答案建立信心,但真正能让你在课程测验里稳住输出的,是这种把知识点拆碎再逐个造句的笨办法。希望帮到你。
本文还有配套的精品资源,点击获取