简介:面向Python初学者和备考者整理的练习题PDF,系统梳理了Python综合练习题目,包含填空、选择、程序改错、程序填空与阅读程序等题型,覆盖基本概念、语法、数据类型、控制结构、函数、模块、异常处理、文件输入输出等核心知识点,并附有答案,便于自测与查漏补缺。资源包共1个文件,类型为PDF,大小1.07MB,便携易用,适合打印或电子阅读。该资料已有706人学习下载,可用于课程考试、等级考试或日常编程巩固。内容针对字符串切片、字典操作、内存管理等易混淆环节设计了典型练习,能帮助读者快速定位薄弱点,提升应试与实操能力。
1. 一份25页的Python试卷,到底在考什么
如果你在搜索框里敲下“Python考试试卷试题整理”,大概率是两类人:一类是刚学完Python基础、想用综合练习题检验自己的初学者,另一类是要给学员或团队出题的讲师、技术组长。一份25页的附答案PDF,放在电子书堆里不算厚,但覆盖的知识密度往往超过很多300页的教程——选择题测语法细节,填空题测函数返回值,编程题测逻辑与调试能力。先别把它当普通文档下载完就扔进收藏夹,真正有用的做法是:把这份试卷当成一份“考点地图”,自己动手拆解每一道题背后的知识点,再用脚本把题目整理成可复用的题库。这篇博客就顺着这条路走一遍:先给题目分层,再教你用Python写一个自动组卷脚本,最后把刷题变成可验证、可追踪的过程。适合刚学完语法但不知道练什么的人,也适合要维护内部题库的开发者。
2. 从练习题到考点地图:Python必考的知识点分层
拿到一份综合练习题,第一件事不是对着答案做,而是把题目按知识点分类。我一般会按四层拆:基础语法与内置函数、函数与作用域、面向对象与异常、文件与模块。这样拆完,复习时就能针对薄弱项定点突破。
2.1 基础语法与内置函数:最容易失分的选择题地带
选择题的干扰项很喜欢考“看似相似但结果不同”的写法。比如range(1, 10, 2)、[1, 2, 3] * 2、'a' + 1,这类题考的是对对象模型和运算符的理解,不是背语法表。整理题目时,我会把每道选择题的选项和正确答案放在一起,然后标注它考核的具体函数或运算符。
| 考点 | 常见考察方式 | 典型坑 |
|---|---|---|
| 可变对象与不可变对象 | 函数参数传递 | 列表作为默认参数被修改 |
| 切片与步长 | 字符串和列表操作 | s[::-1]反转 |
| 内置函数 | map/filter/sorted的返回值 | Python 3 中map返回迭代器 |
| 逻辑运算 | and/or短路求值 | 返回值是操作数而非布尔值 |
做这类题的技巧是:在终端里快速验证一遍,不要只凭记忆。比如sorted([1, -2, 3], key=abs)的结果是什么?写个.py文件跑一下,比背答案有效得多。整理时也可以给每个知识点附一个“最小验证代码”,这样后续复看时能直接看到运行结果。
2.2 函数、作用域与装饰器:闭包是分水岭
函数部分是综合练习题的“分水岭”,闭包和装饰器几乎是必考题。常见的题目是:写出下面代码的输出,然后解释为什么。例如:
def outer(x): def inner(): return x + 1 return inner f = outer(10) print(f())答案当然是11,但考点不止于此。考核点在于:inner捕获了x,outer返回后x依然存活,这就是闭包的定义。整理这类题时,我习惯把“输出结果”和“内存行为”分开记录——前者是答案,后者是原理。
装饰器题更容易变形。比如用functools.wraps保留原函数名,或者带参数的装饰器。答这类题的关键是理解“函数也是对象”,装饰器本质是接收函数并返回新函数的可调用对象。
2.3 面向对象与异常:设计题的标准套路
面向对象的题目往往不是考语法,而是考设计。比如“设计一个银行账户类,支持存款、取款、查询余额,并处理透支异常”。这种题要写完整的类定义,还要注意私有属性、类属性与实例属性的区别。
class Account: bank = 'Python Bank' # 类属性 def __init__(self, owner, balance=0): self._owner = owner # 约定私有 self._balance = balance # 私有余额 def deposit(self, amount): if amount <= 0: raise ValueError('deposit amount must be positive') self._balance += amount def withdraw(self, amount): if amount > self._balance: raise InsufficientFundsError('balance not enough') self._balance -= amount @property def balance(self): return self._balance上面的代码值得注意的点有两个:一是用_前缀表示私有属性,而不是__,因为后者会触发名称重整,容易让初学者困惑;二是自定义异常InsufficientFundsError要继承Exception,这样才能被except捕获。异常部分常考的还有try/except/else/finally的执行顺序——else在无异常时执行,finally无条件执行。
2.4 文件、模块与第三方库:实操题的出题方向
试卷最后的编程题,通常会让考生自己实现一个带文件读写的小工具。比如“读取一个CSV文件,统计每列的平均值,将结果写入JSON文件”。这考察的是open()的上下文管理器、csv模块、json模块,以及路径处理。
import csv import json rows = [] with open('data.csv', 'r', encoding='utf-8') as f: reader = csv.DictReader(f) for row in reader: rows.append(row) if rows: keys = list(rows[0].keys()) result = {} for key in keys: values = [float(r[key]) for r in rows if r[key]] result[key] = sum(values) / len(values) if values else None with open('result.json', 'w', encoding='utf-8') as f: json.dump(result, f, ensure_ascii=False, indent=2)这段代码的注意点是:DictReader的行是OrderedDict,用float(r[key])转换时要处理空值;json.dump设置ensure_ascii=False能让中文正常显示。这个片段本身就是一道很好的综合题,把文件、类型转换、异常处理全串起来了。
3. 用Python脚本自动生成“附答案”试卷:题库整理的正确姿势
当你手里有上百道练习题,手动调整排版和答案顺序太痛苦。我一般会维护一个题库文件,然后用脚本自动抽题、组卷、生成PDF。这样既能保证每次练习的题目不同,也能把答案解析放在一起,省去翻页的麻烦。
3.1 题库数据结构的选型:JSON 还是 CSV
题库的存储方式决定了解析代码的复杂度。如果每道题包含题干、选项、答案、知识点标签,CSV 会因为逗号和换行炸开,所以优先用 JSON。每道题存成字典,整份题库是列表。
[ { "id": 1, "topic": "函数", "question": "下列哪个语句能正确生成一个生成器?", "options": ["(x for x in range(10))", "[x for x in range(10)]", "{x for x in range(10)}", "range(10)"], "answer": "A", "analysis": "生成器表达式使用圆括号" }, { "id": 2, "topic": "内置函数", "question": "abs(-3.14) 的结果是?", "options": ["-3", "3", "3.14", "-3.14"], "answer": "C", "analysis": "abs 返回绝对值" } ]JSON 的好处是天然支持嵌套,答案和解析可以放在同一结构里。字段统一用英文驼峰或下划线,避免中文键在切换环境时编码出问题。
3.2 随机抽题与组卷算法
一份模拟卷要兼顾难度和知识点分布,不能纯随机。我常用的策略是:按知识点分组,再从每组中随机抽取固定数量题目,最后把选定题目打乱顺序。这样既保证覆盖面,又避免相邻题目考查同一个点。
import json import random def load_questions(path): with open(path, 'r', encoding='utf-8') as f: return json.load(f) def build_exam(questions, per_topic=3, shuffle=True): by_topic = {} for q in questions: by_topic.setdefault(q['topic'], []).append(q) selected = [] for topic, qs in by_topic.items(): selected.extend(random.sample(qs, min(per_topic, len(qs)))) if shuffle: random.shuffle(selected) return selected参数说明:per_topic控制每个知识点抽几道,设为 0 则跳过该知识点;shuffle为真时会打乱最终题目顺序,模拟真实考试试卷的混合出题。如果题库里某个知识点题目不够,random.sample会抛异常,所以用min()限制抽取数量。这样的组卷脚本,足够支撑一份25页左右的PDF练习册。
3.3 生成带答案的PDF:reportlab 与 markdown 的取舍
生成PDF有两条路:用reportlab直接绘制,或者先把内容转成 markdown 再用工具转PDF。reportlab的优点是最终排版可控,适合中英文混排和代码块;缺点是API较底层,写起来繁琐。我一般只生成题目、选项和答案表格,不处理复杂公式,所以用reportlab就很顺手。
from reportlab.lib.pagesizes import A4 from reportlab.pdfgen import canvas from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase import pdfmetrics pdfmetrics.registerFont(TTFont('SimSun', 'SimSun.ttf')) # 中文字体 def save_pdf(selected, output_path): c = canvas.Canvas(output_path, pagesize=A4) width, height = A4 y = height - 40 for i, q in enumerate(selected, 1): if y < 100: c.showPage() y = height - 40 c.setFont('SimSun', 10) text = f"{i}. ({q['topic']}) {q['question']}" y = draw_text(c, text, width - 80, y) for j, opt in enumerate(q['options']): y -= 18 c.drawString(60, y, f"{'ABCD'[j]}. {opt}") y -= 18 c.setFont('SimSun', 9) c.setFillColorRGB(0.4, 0.4, 0.4) c.drawString(60, y, f"答案: {q['answer']} 解析: {q['analysis'][:30]}...") y -= 30 if y < 80: c.showPage() y = height - 40 c.save() def draw_text(c, text, max_width, y): # 按宽度截断,避免超界 while c.stringWidth(text) > max_width: line = text[:int(len(text)/2)] c.drawString(50, y, line) y -= 15 text = text[int(len(text)/2):] c.drawString(50, y, text) return y - 15 save_pdf(exam_questions, 'exam.pdf')这里的draw_text是简陋的按半宽截断实现,实际工作中建议引入textwrap按字符宽度处理。中文PDF一定要注册中文字体,否则会显示乱码或方块。canvas对象写满一页后调用showPage()自动翻页,这是生成多页PDF的关键。
3.4 参数说明与运行效果
运行组卷脚本时,我通常会加两个参数:一个是--seed,传入随机种子,保证同一份试卷可以复现;另一个是--answer开关,控制生成的PDF是否附带答案。考试版和练习版用同一份题库,只是输出不同。
python build_exam.py --per-topic 5 --seed 42 --output exam.pdf python build_exam.py --per-topic 5 --answer --output exam_with_answer.pdf--seed很重要。随机组卷如果不指定种子,每次生成结果都不同,不方便下次讲解同一道题。设置同一个种子,random会生成相同的随机序列,同时也便于回归测试——题库改动后,对比新旧试卷题目是否仍符合预期。
4. 综合练习题的答案解析:5个必考易错点拆解
整理“附答案”的试卷,本质上是在整理易错点。下面这5个点几乎是每套综合练习题的常客,答案背下来不难,但能讲清楚为什么才算掌握。
4.1 可变对象默认参数:def f(lst=[]) 的陷阱
def add_item(item, lst=[]): lst.append(item) return lst print(add_item(1)) # [1] print(add_item(2)) # [1, 2] 而不是 [2]默认参数在函数定义时被求值一次,之后所有调用共享同一个列表对象。所以每次调用add_item修改的都是同一个默认列表。把它改成lst=None,函数体内再判断:
def add_item(item, lst=None): if lst is None: lst = [] lst.append(item) return lst这是标准解法,关键词是“可变对象默认参数”。题目里经常把[]换成{}或set(),原理一致。
4.2 作用域链与nonlocal:闭包计数器的正确写法
def counter(): count = 0 def inc(): count += 1 # UnboundLocalError return count return inccount += 1在inc内部会创建一个新的局部变量,因为赋值操作让解释器把它视为局部变量。解法是在inc内声明nonlocal count。考题常问“输出是什么”或“如何修复”,回答时要说明nonlocal的作用是让内层函数能修改外层函数的局部变量。
4.3 列表解析与生成器:内存与效率的平衡
一个经典题是:计算[i * i for i in range(10000)]和(i * i for i in range(10000))的区别。前者生成完整的列表,占用内存;后者生成生成器对象,逐个求值。如果题目让计算sum(i * i for i in range(10000)),用生成器表达式不会创建大列表,这是更优写法。考场上经常混淆的就是圆括号和方括号的差异。
4.4 浅拷贝与深拷贝:copy模块的边界
import copy a = [[1, 2], [3, 4]] b = a[:] # 浅拷贝,内层列表仍是同一对象 b[0][0] = 99 print(a) # [[99, 2], [3, 4]]a[:]拷贝了外层列表,但没有拷贝内层列表。只有使用copy.deepcopy才会递归复制所有嵌套结构。考题里如果出现b[0] is a[0],答案就是True。整理这类题时,我会画一个简单的引用图,把可变对象和不可变对象的关系标出来。
4.5 异常链与自定义异常:print还是raise
def divide(a, b): if b == 0: raise ZeroDivisionError('division by zero') return a / b try: divide(1, 0) except ZeroDivisionError as e: print('错误:', e) raise # 继续抛出,保留原始堆栈raise不带参数会把当前异常重新抛出,保留堆栈信息。如果写raise e,虽然也能抛,但会丢失原始异常上下文。Python 3 中的raise ... from e还能显式添加异常链。题目常考的是:捕获异常后是打印还是重新抛出?答案取决于调用方是否需要知道错误。如果只是提示用户,print即可;如果是库代码,必须raise。
5. 刷题效率翻倍:把这25页变成自动化的错题本
把PDF里的题目变成可执行的代码,是比反复翻阅答案更高效的复习方式。我通常会将每道能运行的题写成一个独立的.py,然后用pytest断言答案,再结合间隔重复策略安排复习时间。
5.1 用pytest给每道题写测试断言
比如一道题是“编写函数,返回列表去重后的元素个数”,可以用一个测试文件锁住它:
# test_exercise.py def count_unique(lst): return len(set(lst)) def test_count_unique(): assert count_unique([1, 2, 2, 3, 3, 3]) == 3 assert count_unique([]) == 0 assert count_unique(['a', 'a', 'b']) == 2运行pytest -v test_exercise.py,每个断言都通过,才算真正把这道题做对了。比对着答案看“哦,应该是3”要强得多。即使试卷里的题目没有要求写函数,你也可以自己把答案改写成一个可测试的函数,顺便练习封装能力。
5.2 错题重练的间隔重复策略
我会为错题在题库里打一个wrong_count字段,每次做错就加一,正确一次减一。组卷脚本优先抽取wrong_count高的题目,并且让这些题间隔两次练习后再出现,类似Anki的间隔重复。
def prioritize(questions): return sorted(questions, key=lambda q: -q.get('wrong_count', 0)) selected = prioritize(qs)[:10]这样每一次练习都是针对薄弱点,而不是从头到尾泛泛刷。同时,每道错题补一句“为什么错”,下次再看到时能快速回忆起失误原因。25页的PDF只是一个起点,把它的内容拆解成结构化题库、生成可复现的试卷、用pytest验证答案,你得到的是一套可以持续迭代的个人刷题系统。
本文还有配套的精品资源,点击获取