简介:这是一套Python综合练习题库,专为Python初学者、备考计算机等级考试的考生以及需要布置随堂练习的教师设计。题库围绕语言基础、数据类型、控制结构、函数、模块、异常处理和文件输入输出等核心知识点展开,题型包含填空题、选择题、程序改错题、程序填空题和阅读程序题,能较全面地检测对Python语法的理解与运用能力。资源以单个PDF文件提供,包体大小仅1.07MB,在电脑、平板或手机上均可流畅查阅,也适合打印后离线刷题。当前已有706人学习下载,内容实用性得到初步验证。除了完整题目外,资料还附带参考答案与改错题的纠错说明,方便读者逐题核对并理清易混淆概念。选择题和填空题适合碎片化自测,程序改错与阅读题则有助于锻炼调试思维和代码阅读能力,无论是考前集中突破还是日常巩固都非常适用。
1. 一份老题集的新用法:先摸清 Python 基础的真实水位
这套 25 页的 Python 综合练习卷,是典型的期末卷结构:填空、单选、程序改错、程序填空、读程序写结果五大块。题目是 Python 2 时代的措辞,但考的东西正好是贴着语言底层来的——切片下标边界、变量与对象引用、字典的构造与查询、循环边界。这类题经过多年反复使用,反而筛出了今天很真实的坑:很多人学会用框架和第三方库推进度,一回到语法语义级别就露馅。
我建议三类人拿它当基准测试:刚学完 Python 基础想检验自己的入门者;带新人想快速摸底的技术负责人;准备考试或面试前想查漏补缺的人。方法很简单:不看答案完整做一遍,做错的题按知识点分类,再回补对应语法。下面按题型逐层拆解,重点讲怎么做、怎么验、坑在哪。
2. 填空题拆解:注释、模块与切片边界
填空题是最能暴露“凭记忆学语言”还是“按规则学语言”的题型。表面看是填几个符号,实际上每一空都在考语言规范里的细节。
2.1 注释、续行与模块导入的规范写法
题目要求填写注释符号、续行符和导入关键字。标准答案是#、\、import。以 Python 3 环境验证:
# 这是注释 total = 1 + 2 + \ 3 + 4 # 反斜杠续行,后面不能有空格或注释 words = ("hello " "world") # 括号内隐式拼接,更推荐 import sys # 导入模块注意三点:反斜杠续行后不能再出现任何字符,否则报语法错误;三引号字符串不是续行符号,它只是创建了一个包含换行符的字符串对象,老答案里“用三引号续行”的说法是混淆了字符串字面量与续行语法;除了import,还有from ... import ...和import ... as ...两种变体,填空题里的“关键字”特指import本身。实际编码中,续行优先用括号包裹,因为反斜杠在代码格式化工具下容易出问题。
2.2 切片下标边界:左闭右开与负数步长
原题给字符串s = 'abcdefg',要求写出 7 个切片表达式的结果。这个考点只需要记住两条规则就能全对:切片是左闭右开,[start:stop]包含 start 不包含 stop;步长为负数时从右向左取,但仍遵循 start 取得到、stop 取不到的原则。
| 表达式 | 结果 | 说明 |
|---|---|---|
s[3] | 'd' | 下标 3 是第 4 个字符 |
s[3:5] | 'de' | 包含下标 3,不含下标 5 |
s[:5] | 'abcde' | 省略 start 默认从 0 开始 |
s[3:] | 'defg' | 省略 stop 默认到末尾 |
s[::2] | 'aceg' | 步长 2,间隔取字符 |
s[::-1] | 'gfedcba' | 步长 -1,整体倒序 |
s[-2:-5] | '' | -2 在 -5 右侧,正向切为空 |
最后一行的s[-2:-5]是经典陷阱。很多人觉得负下标就该“倒着取”,实际上切片方向由步长决定,这里步长默认是 1,所以从 -2 向右找不到 -5,结果为空字符串。要想得到预期的'fed',必须写成s[-2:-5:-1]。Python 对切片越界非常宽容:s[100:200]不报错,返回空;s[-100:100]会从真正起点切到真正终点。这在处理不定长字符串时很有用,但也意味着切片错误不会直接暴露,只能靠测试覆盖。
2.3 字典方法对照:clear、keys、values 与存在性判断
填空最后一道是关于字典的四个操作:清空、取键列表、取值列表、判断键是否存在。Python 2 与 Python 3 在这里有个显著差异,老答案里写的是has_key(),这在 Python 3 里已经被删除。
d = {"name": "py", "ver": 3} d.clear() print(d) # {} d = {"name": "py", "ver": 3} print(list(d.keys())) # ['name', 'ver'] print(list(d.values())) # ['py', 3] print("name" in d) # True,Python 3 推荐写法| 功能 | 老写法 | Python 3 写法 |
|---|---|---|
| 清空字典 | d.clear() | d.clear() |
| 取出全部键 | d.keys() | list(d.keys()) |
| 取出全部值 | d.values() | list(d.values()) |
| 判断键是否存在 | d.has_key(k) | k in d |
注意d.keys()在 Python 3 里返回的是视图对象,直接打印能看到内容,但它不是列表,不能按下标访问。需要下标就得套list()。判断键存在用in操作符,它不是函数,不要写成in(k)。刷题时建议直接开一个 Python 3.8+ 环境把这些方法跑一遍,比背 API 列表管用。
3. 选择题陷阱:引用共享、真值测试与字典构造
选择题不单纯考概念,更考运行时细节。这套题里有几道是每年都有人错的,错的原因不是不知道语法,而是对 Python 对象模型理解不透。
3.1 列表引用共享:list2 为何跟着 list1 变
原题是list1 = [4,5,6],执行list2 = list1,然后list1[2] = 3,问list2的值。不少人选[4,5,6],实际运行结果是[4,5,3]。
list1 = [4, 5, 6] list2 = list1 # 赋值只绑定引用,不复制对象 list1[2] = 3 print(list2) # [4, 5, 3] print(list1 is list2) # True,两个名字指向同一个对象原因在于 Python 的赋值操作不复制对象,只是把一个名字绑定到已有对象上。list2 = list1让两个变量指向同一块内存,后续通过任何一个名字修改都会互相影响。要真正得到独立副本,必须显式复制:list2 = list1.copy()或list2 = list1[:]。这个坑在函数传参时变体最多:在函数体内直接 append 或修改元素,调用方的数据也被改了。一个排查技巧是打印id(list1) == id(list2),看到相同 id 就能确认是引用共享。
3.2 真值测试规则:字典也能参与布尔判断
原题问“下列哪种说法是错误的”,其中有个选项是“除字典类型外,所有标准对象均可以用于布尔测试”。这套老答案给的回复是选这个选项,但这句话本身在 Python 3 里并不成立——字典完全可以用在布尔测试中,空字典为假,非空字典为真。
print(bool({})) # False,空字典 print(bool({"a": 1})) # True,非空字典 print(bool("")) # False print(bool([])) # False print(bool(0)) # False print(bool(None)) # FalsePython 3 的规则统一为:None、False、数值 0、空字符串、空列表、空字典、空元组、空集合等都为假,其他对象为真。而且任意对象都能直接用于if或while条件,不存在“某种类型不能布尔测试”的说法。这题选错的人往往把bool()函数和“对象是否可比较”搞混。另一个易错点是复数:5+4j > 2-3j会直接抛TypeError: '>' not supported between instances of 'complex' and 'complex'。复数没有大小比较,这在涉及坐标或频域数据时尤其容易踩。
3.3 字典构造:位置参数个数与可迭代对象
原题让选“不能创建字典的语句”,里面有两个选项是dict([2,5],[3,4])和dict(([1,2],[3,4]))。前一个非法,后一个合法。
d1 = {} # 合法,空字典 d2 = {3: 5} # 合法,字面量 d3 = dict([(2, 5), (3, 4)]) # 合法,键值对列表 d4 = dict(([1, 2], [3, 4])) # 合法,键值对元组 d5 = dict(zip(["a", "b"], [1, 2])) # 合法,zip 打包键值对 # d6 = dict([2, 5], [3, 4]) # TypeError核心规则是dict()构造时只接受一个位置参数,这个参数必须是可迭代对象,迭代出的每个元素本身也是可迭代对象且长度为 2。dict([2,5],[3,4])相当于传了两个位置参数,直接违反函数签名。dict(([1,2],[3,4]))里外层括号构造了一个元组,元组里是两个列表,满足“一个可迭代对象”的条件。实际写代码时用dict(zip(keys, values))最直观,因为 zip 的结果正好是键值对的可迭代对象。
4. 程序改错与读程序:从语法迁移到循环边界
拿到程序改错题别急着动手改。先通读一遍确定程序想干什么,再逐行检查语法,最后核对逻辑边界。这套题里的标识符检查程序,把老 Python 与新 Python 的差异集中在一个例子里。
4.1 Python 2 迁移 Python 3:print、raw_input 与切片语法
改错题原文是 Python 2 风格,放到 Python 3 下会有多处硬伤:print后面缺括号、raw_input()不存在、s(1:)用圆括号做切片。先把修正版写出来:
s = "hello" # 原程序用 raw_input 读入,这里是演示 alphas = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_' nums = "0123456789" if len(s) > 1: first_char = s[0] if first_char not in alphas + nums: print('Error. First char must be alphas or number.') else: other_chars = s[1:] alphas_nums = alphas + nums for c in other_chars: if c not in alphas_nums: print('Error. Other chars must be alphas number or _ .') break else: print("okay as an identifier")改动的关键点有三个:raw_input换成input,如果考试环境仍是 Python 2 则保持原样;切片必须用方括号语法s[1:],原题的s(1 : )是函数调用写法,字符串对象不可调用所以必错;for...else结构里,else分支只在循环没有被 break 中断时执行,正好用来表示“所有字符都合法”。
这个例子非常适合做代码审查训练。老项目里经常能看到 Python 2 语法残留,比如print无括号、xrange、dict.has_key。直接跑一遍 Python 3 解释器会立刻报错,但改错题的价值在于让你能一眼看出问题,而不是等运行时报错再定位。
4.2 循环次数边界:while 与 range 的差一问题
原题有一道“哪个循环执行次数与其他不同”,四个选项看都能数出来,关键在于边界:
| 循环写法 | 执行次数 | 取值区间 |
|---|---|---|
while i <= 100: i += 1 | 101 次 | 0 到 100 |
for i in range(100): | 100 次 | 0 到 99 |
for i in range(100, 0, -1): | 100 次 | 100 到 1 |
while i > 0: i -= 1 | 100 次 | 100 到 1 |
第一组比其他多一次,因为<=把 100 也算进去了。这种差一错误在分页接口里最典型:start = (page - 1) * size,end = start + size,如果切片写成list[start:end+1]就会多取一条。排查方法很简单:打印循环里的下标集合,确认首尾值是否符合预期。做题时尤其要区分range(n)是 0 到 n-1 还是 1 到 n,这一步错了后面全错。
4.3 读程序题的状态表推导法
读程序写结果不要凭感觉心算,直接在纸上画变量状态表。原题那个双重循环排序的例子,实际执行的是单趟冒泡:从下标 0 开始,每次比较a[i]和a[i+1],前一个大于后一个就交换。
a = [1, 20, 32, 14, 5, 62, 78, 38, 9, 10] for i in range(9): if a[i] > a[i+1]: a[i], a[i+1] = a[i+1], a[i] print(a)逐步推演关键交换:
i=2: 32>14,交换 -> [1, 20, 14, 32, 5, 62, 78, 38, 9, 10] i=3: 32>5, 交换 -> [1, 20, 14, 5, 32, 62, 78, 38, 9, 10] i=6: 78>38,交换 -> [1, 20, 14, 5, 32, 62, 38, 78, 9, 10] i=7: 78>9, 交换 -> [1, 20, 14, 5, 32, 62, 38, 9, 78, 10] i=8: 78>10,交换 -> [1, 20, 14, 5, 32, 62, 38, 9, 10, 78]最终结果是[1, 20, 14, 5, 32, 62, 38, 9, 10, 78]。这里有个判断技巧:循环只跑 9 次,也就是从头到尾扫描一遍,最大值 78 一定被交换到末尾,但前面的序列仍然无序。如果你算出完全有序的结果,说明把外层循环的次数也当成 9 次了,那就错了。读程序题常考“单趟效果”,因为很多人看到冒泡就默认输出完整排序结果,忽略了外层循环只跑了一次。
5. 用 40 行代码把题库变成自动化自测脚本
做完一遍题之后,最有价值的动作是把错题固化成一个可重复的自测工具。这里提供一个轻量做法:把选择题整理成字典,按知识点分组,随机抽题并判分,答错时输出提示。用 Python 3 直接运行。
import random questions = { "引用": { "q": "list1=[4,5,6]; list2=list1; list1[2]=3 后 list2 是?", "options": ["[4,5,6]", "[4,3,6]", "[4,5,3]", "报错"], "answer": 2, "hint": "赋值是引用绑定,不是复制" }, "真值": { "q": "下列哪个对象的布尔值为 False?", "options": ["0", "[0]", "{'a':1}", "'False'"], "answer": 0, "hint": "数值 0、空容器、None、False 为假" }, "字典构造": { "q": "哪个语句不能创建字典?", "options": ["{}", "{3:5}", "dict([2,5],[3,4])", "dict(([1,2],[3,4]))"], "answer": 2, "hint": "dict() 只接受一个可迭代位置参数" } } def quiz(pool): key = random.choice(list(pool)) item = pool[key] print(f"\n[{key}] {item['q']}") for i, opt in enumerate(item["options"]): print(f"{i}. {opt}") choice = int(input("输入序号: ")) if choice == item["answer"]: print("正确") else: print(f"错误,提示:{item['hint']}") for _ in range(5): quiz(questions)核心是题目数据与判分逻辑分离:questions里每个知识点一张卡片,answer存选项下标,新增题目只需往字典里加记录,判断逻辑不用动。这个脚本本身也能帮你复习——写字典构造选项时,你就得想清楚哪个选项会抛 TypeError;写答案下标时,你会再次核对列表从 0 开始还是从 1 开始。
如果你已经整理出自己的错题集,可以再加一个加权抽样:给每个知识点维护一个weight,答错后权重加 1,下次抽中概率更高,用random.choices(list(pool.keys()), weights=weights)实现。每次练习结束后把结果写入 JSON 文件,回头就能看到哪些知识点反复出错。把 25 页静态 PDF 变成交互式自测环境,这个过程本身就会把当年做错的考点再串一遍——从字典操作到随机抽样,从输入类型转换到循环控制,相当于用代码重新验证了一遍这套题的全部答案。
本文还有配套的精品资源,点击获取