引言
课程 01 进入第十章「阶段测验与查漏补缺」。本篇是阶段测验一,把前三章(第 1 章环境搭建与运行原理、第 2 章变量/类型/运算符、第 3 章流程控制)的知识做一次系统检验。读者应当已经学完第 001-009 章对应的前九个章节内容(学习路径见第一章第 1 篇),并独立通过第二章与第三章的章末测验。本篇的定位不是教学而是诊断:通过十道选择题检验「记忆是否牢固、概念是否理解、场景能否应用」三层能力,再用两道编程题检验动手能力——选择题可以蒙对,编程题蒙不出来,两道编程题都能独立完成,才说明前三章真正长在了手上。
所有代码与运行结果均在本机 CPython 3.12.10(Windows 11 + Git Bash)实测,代码块全部自包含、可直接运行复现。建议先做完题再翻解析:做错的题不要只看答案,回到出处标注的对应篇章重读原理。
测验说明:覆盖范围与难度分布
十道选择题按「记忆 → 理解 → 应用」梯度排列,每题标注出处与考点,覆盖如下:
- 第 1 章(环境与运行原理):1 题(版本信息与解释器),侧重「环境会说话」——先确认解释器是谁,再谈代码表现。
- 第 2 章(变量、类型与运算符):5 题,覆盖引用语义(
is与==)、浮点误差、真值测试与短路、类型转换边界、f-string 格式规约五个高频考点。 - 第 3 章(流程控制):4 题,覆盖 match 模式捕获、while 与 break/else、range 步长、条件推导式。
难度分布:记忆 2 题、理解 5 题、应用 3 题。记忆题考「规则是什么」,理解题考「为什么如此」,应用题考「换个场景还会不会」。建议每题限时两分钟,全部做完后按答案核对,错题超过 3 道应回到对应篇章重读再进入编程题。
选择题(共 10 题,每题只有一个正确答案)
第 1 题:解释器的版本信息【记忆】(出处:第 1 章「Python 安装与配置」「解释器与 CPython」)
import sys
print(sys.version_info.major, sys.version_info.minor)
运行 python q1.py,输出是什么?
A. 3.12.10
B. 3 12
C. (3, 12, 10)
D. 3 12 10 f
第 2 题:== 与 is 的差别【理解】(出处:第 2 章「变量与赋值」)
a = [1, 2, 3]
b = a
c = [1, 2, 3]
print(a == b, a is b, a == c, a is c)
输出是什么?
A. True True True True
B. True True True False
C. True False True False
D. False False True False
第 3 题:浮点数的相等判断【记忆】(出处:第 2 章「数字类型」)
print(0.1 + 0.2 == 0.3)
print(round(2.675, 2))
输出是什么?
A. True 和 2.68
B. False 和 2.67
C. True 和 2.67
D. False 和 2.68
第 4 题:短路运算的返回值【理解】(出处:第 2 章「布尔值与真值测试」)
print(0 or '默认值')
print(1 and 2)
print([] or [0])
输出是什么?
A. 0、2、[]
B. 默认值、2、[0]
C. 默认值、True、[0]
D. 0、True、[]
第 5 题:类型转换的边界【理解】(出处:第 2 章「类型转换」)
print(int(3.99))
print(bool('False'))
print(int(' 42 '))
输出是什么?
A. 3、False、42
B. 3、True、42
C. 4、True、42
D. 3、True、42 (带空格)
第 6 题:f-string 格式规约【应用】(出处:第 2 章「f-string 与字符串格式化」)
price = 1234567.891
print(f'{price:,.2f}')
print(f'{255:#x}')
print(f'{"ok":*^8}')
输出是什么?
A. 1,234,567.89、0xff、***ok***
B. 1,234,567.89、255x、**ok**
C. 1,234,567.89、0xff、*ok*
D. 1234567.89、ff、***ok***
第 7 题:match 中的裸名字捕获【理解】(出处:第 3 章「match-case 模式匹配」)
command = 'A100'
match command:
case 'A999':
result = '特批单'
case 'A000':
result = '未知'
case msg:
result = f'普通单据:{msg}'
print(result)
输出是什么?
A. 特批单
B. 未知
C. 普通单据:A100
D. 抛 SyntaxError
第 8 题:while 与 break/else 的组合【应用】(出处:第 3 章「break / continue / else」)
n = 0
while n < 5:
n += 1
if n == 3:
break
else:
print('循环自然结束')
print(n)
输出是什么?
A. 先打印 循环自然结束 再打印 5
B. 只打印 5
C. 先打印 3 再打印 循环自然结束
D. 只打印 3
第 9 题:range 的步长与求和【记忆】(出处:第 3 章「for 循环与 range」)
total = 0
for i in range(1, 6, 2):
total += i
print(total)
输出是什么?
A. 6
B. 9
C. 10
D. 15
第 10 题:带条件的字典推导式【应用】(出处:第 3 章「推导式」)
nums = [1, 2, 3, 4, 5]
result = {n: n * n for n in nums if n % 2 == 1}
print(result)
输出是什么?
A. {1: 1, 4: 4, 9: 9, 16: 16, 25: 25}
B. {1: 1, 9: 9, 25: 25}
C. {1: 1, 3: 9, 5: 25}
D. [1, 9, 25]
点击查看答案
答案:B B B B B A C D B C
第 1 题(B):sys.version_info 是一个具名元组,major 与 minor 分别是主版本号 3 和次版本号 12,打印两个字段得到 3 12。它和 python --version 输出的 Python 3.12.10 是同一信息的两种来源:命令看给人,sys.version_info 看给程序(比如脚本开头校验最低版本)。在哪台机器、哪个 Python 上跑,直接决定了后面所有行为,这是第 1 章要建立的第一直觉。
第 2 题(B):== 比较值(内容),is 比较身份(是否同一个对象)。b = a 让 b 与 a 引用同一列表,所以 a == b 与 a is b 都是 True;c = [1, 2, 3] 新建了一个内容相同的列表,a == c 为 True 而 a is c 为 False。用 id() 观察两句话更直观:绑定不复制,字面量每次都新建——这是「名字是引用」的核心。
第 3 题(B):float 是 IEEE 754 双精度,0.1 与 0.2 在二进制里都是无限循环小数,先各自舍入再相加,结果与 0.3 的舍入值差一个极小误差,因此 == 为 False。round(2.675, 2) 的结果是 2.67 而不是 2.68——2.675 在内存里实际是 2.6749999…,四舍五入后落回 2.67。需要精确比较时用 math.isclose,需要精确小数时用 decimal.Decimal。
第 4 题(B):and 与 or 在 Python 里返回的是操作数本身而不是布尔值:or 遇到真值就短路返回它(0 or '默认值' 返回 '默认值'),and 遇到假值就短路返回它(1 and 2 一路为真、返回最后一个操作数 2)。[] or [0] 里空列表是假值,于是返回 [0]。这是「真值测试」的延伸:if 判断的是对象真假,短路表达式拿回的是对象,两者配合才能写出 user_input or '默认' 这类惯用法。
第 5 题(B):int(3.99) 向零截断得 3(不是四舍五入);bool('False') 是非空字符串,任何非空字符串都是真值,得 True;int(' 42 ') 允许首尾空白,得 42。真正的坑在别处:int('3.14') 会抛 ValueError(只认整数语法),int('0xff') 也得显式传 base 才能解析。记住三句话:int 截断、字符串判真看非空、字符串转数字看语法。
第 6 题(A):三个格式规约依次是:千分位分隔符 , 加两位小数;#x 输出带 0x 前缀的小写十六进制;*^8 表示用 * 填充、居中对齐、总宽 8。宽度 8 的居中算法是 (8 - 2) / 2,左右各补 3 个 *,得到 ***ok***。这类「格式规约八段语法」在第五章第八篇还有深度考法,这里先确认基础段位。
第 7 题(C):裸名字(如 msg)不是常量比较,而是捕获模式——它无条件匹配并把被匹配的值绑定给这个名字。A100 不匹配前两个常量模式,落到 case msg,于是输出 普通单据:A100。注意两个细节:捕获模式放在最后才合法——若把它放在中间,后面的模式永远不会被执行,CPython 3.12 会直接报 SyntaxError: name capture 'msg' makes remaining patterns unreachable,这是本机实测遇到的真实报错;另外「未知」分支永远不会触发,因为 case msg 抢走了所有剩余输入。
第 8 题(D):while 的条件是「先测、为真再进」。n 从 0 开始,第 1 次进循环 n 变 1,第 2 次变 2,第 3 次变 3 时命中 if n == 3 执行 break,循环被提前终止。else 子句只在循环没有被 break 打断时执行,这里被 break 打断,所以只打印 3。for-else/while-else 是省掉标志位的惯用法:用「是否被打断」代替「是否找到」,语义更直接。
第 9 题(B):range(1, 6, 2) 是「从 1 开始、小于 6、步长 2」的惰性序列,展开为 1、3、5(不含 6),求和得 9。range 不生成列表、按需产出,这也是它内存高效的原因;第 3 章里 enumerate、zip 与 range 的组合是遍历场景的三板斧。
第 10 题(C):字典推导式 {键: 值 for 元素 in 可迭代 if 条件} 与列表推导式同构,只是把收集目标换成键值对。这里只对奇数 n 建立 n: n*n 映射,得到 {1: 1, 3: 9, 5: 25}。推导式是「循环+收集」的一行化,但超过两行逻辑时请退回普通 for 循环——可读性优先是第 3 章的结论,不是禁止而是取舍。
编程题(共 2 题,附可运行参考解答)
编程题 1:猜数字增强版
题目:基于第三章第八篇的猜数字,加四个增强:①输入必须能被 isdigit() 通过,否则提示重试(不许程序崩溃);②猜测必须在 1-100 之间,越界提示重试;③每次猜测后给「大了/小了」的二分提示,并统计次数;④支持随时输入 q 退出;猜中后按次数给出三档评价(≤5 次、≤8 次、更慢)。核心逻辑放进 play(secret, input_fn=input, output_fn=print) 函数,input_fn 与 output_fn 可注入,便于自动化测试。
参考解答:
"""猜数字增强版:范围校验、非法输入重试、二分提示、次数统计、随时退出。"""
def play(secret, input_fn=input, output_fn=print):
output_fn('猜数字游戏开始,目标在 1-100 之间;输入 q 随时退出。')
attempts = 0
while True:
raw = input_fn('请输入你的猜测:')
text = raw.strip()
if text.lower() == 'q':
output_fn('已退出游戏,下次再战。')
return None
if not text.isdigit():
output_fn('输入不是整数,请重新输入。')
continue
guess = int(text)
if not 1 <= guess <= 100:
output_fn('数字超出 1-100 范围,请重新输入。')
continue
attempts += 1
if guess > secret:
output_fn(f'第 {attempts} 次:猜大了。')
elif guess < secret:
output_fn(f'第 {attempts} 次:猜小了。')
else:
output_fn(f'恭喜!第 {attempts} 次猜中。')
if attempts <= 5:
output_fn('评价:神枪手!')
elif attempts <= 8:
output_fn('评价:稳扎稳打。')
else:
output_fn('评价:下次可以再快一点。')
return attempts
if __name__ == '__main__':
play(secret=42)
把 play(secret=42) 放到 if __name__ == '__main__' 里,文件既能被测试 import,又能独立运行。本机用管道把一次完整会话(含非法输入 abc、越界 150、以及 20→50→35→42 的一次二分逼近)喂给程序,实测输出如下:
猜数字游戏开始,目标在 1-100 之间;输入 q 随时退出。
请输入你的猜测:输入不是整数,请重新输入。
请输入你的猜测:数字超出 1-100 范围,请重新输入。
请输入你的猜测:第 1 次:猜小了。
请输入你的猜测:第 2 次:猜大了。
请输入你的猜测:第 3 次:猜小了。
请输入你的猜测:恭喜!第 4 次猜中。
评价:神枪手!
关键点:非法输入用 continue 跳过本轮而不是 break,目标数字落在 1-100 内时二分提示保证 7 次以内必然命中(log2(100) ≈ 6.64);isdigit() 先于 int() 把关,让「转换永远成功」。把这两个防御顺序记住,第五章之后读文件、第七章之后做校验都会反复用到这个模式。
编程题 2:温标换算菜单
题目:写一个交互式菜单:输入 c2f 进入摄氏转华氏(F = C × 9/5 + 32),输入 f2c 进入华氏转摄氏(C = (F - 32) × 5/9),输入 q 退出;无效选项与非法数字都要提示重试而不是崩溃;结果用 {:.1f} 保留一位小数输出。要求把两个换算公式写成独立函数,主流程只负责菜单与输入校验。
参考解答:
"""温标换算菜单:摄氏与华氏互转,无效输入重试,q 退出。"""
def c_to_f(celsius):
return celsius * 9 / 5 + 32
def f_to_c(fahrenheit):
return (fahrenheit - 32) * 5 / 9
def run(input_fn=input, output_fn=print):
output_fn('温度转换菜单:输入 c2f 摄氏转华氏,f2c 华氏转摄氏,q 退出。')
while True:
choice = input_fn('请选择操作:').strip().lower()
if choice == 'q':
output_fn('再见!')
return
if choice not in ('c2f', 'f2c'):
output_fn('无效选项,请输入 c2f / f2c / q。')
continue
try:
value = float(input_fn('请输入温度数值:'))
except ValueError:
output_fn('温度必须是数字,请重新操作。')
continue
result = c_to_f(value) if choice == 'c2f' else f_to_c(value)
output_fn(f'结果:{result:.1f}')
if __name__ == '__main__':
run()
本机用管道把输入序列 x → c2f 100 → f2c 212 → q 喂给程序(input() 的提示语与下一行输出连在同一行),实测如下:
温度转换菜单:输入 c2f 摄氏转华氏,f2c 华氏转摄氏,q 退出。
请选择操作:无效选项,请输入 c2f / f2c / q。
请选择操作:请输入温度数值:结果:212.0
请选择操作:请输入温度数值:结果:100.0
请选择操作:再见!
关键点:公式独立成纯函数(无输入输出副作用)是第四章的前提;100°C 转华氏恰好 212°F、212°F 转回 100°C,两个数互为验算,这说明公式与浮点舍入都对。菜单循环的四件套——while True 常驻、strip().lower() 归一化输入、continue 重试、q 出口——是第 3 章第 9 篇交互式菜单的完整骨架,能默写这四件套,前九章的所有 CLI 小项目都有了地基。
小结
本测验用 10 道选择题与 2 道编程题复核了前三章:环境层要知道「解释器是谁、版本能告诉程序什么」;数据层要知道「名字是引用、== 看值 is 看身份、float 有误差、bool 判真值、类型转换有四道边界」;控制层要知道「match 的裸名字是捕获、while/for 的 else 只在未被打断时执行、range 是惰性的、推导式是循环+收集的一行化」。两道编程题共同指向一个工程习惯:输入永远不可信,校验放在转换之前,逻辑与 I/O 分离。做错的题请回到出处篇章重读,这比多做新题更有效。
练习与自检清单
- 自检题:把第 10 题改成「只取奇数、且数值大于 2」的字典推导式,先手写输出再运行核对;再想想为什么
{n: n*n for n in nums}与dict((n, n*n) for n in nums)结果等价(提示:两者收集的都是键值对)。 - 改造练习:给温标菜单加第三个选项
k2c(开尔文转摄氏,C = K - 273.15),并让非法选项的错误提示里列出当前支持的选项——答案导向:公式入函数表、提示用 f-string 动态生成。 - 反向练习:运行
python -c "import sys; print(sys.version)"与第 1 题的输出对比,说出sys.version与sys.version_info的返回类型差异;再运行python -m this感受解释器自带的哲学文本(第 1 章的彩蛋)。 - 自查清单:能默写
==/is的区别并说出小整数缓存的边界(-5 到 256,第 2 章第 1 篇);能说出and/or返回操作数而非布尔这一条;能手写「未被打断才执行」的 while-else;能解释推导式与 for 循环的取舍。全部打勾后,进入阶段测验二(第 4-7 章字符串、容器与文件)。