Python 三天高中密集集训:练习设计、收尾项目规格与现代化工具链(Python 3.14 + uv + pytest + ruff)调研报告¶
一句话摘要:基于 2026 年 9 月最新的 Python 3.14.4 与 uv 0.9.21 生态,结合 Harvard CS50P、Exercism 与 Codewars 题库范式,制定覆盖 6 种练习设计模式、3 个 3 小时收尾项目规格、以及轻量化 pytest/ruff 工程化交付标准的初学者集训方案。 调研日期:2026-09-05
一、 核心结论(面向计划编写者的可执行要点)¶
- 练习组织递进原则(Scaffolding 渐进式支架):高中生在短时间内吸收大量概念,练习设计必须打破单一的从零手写,严格遵循读代码预测输出 -> 找 Bug(1-2行修复) -> 填空(Fill-in-the-blank) -> 乱序重排(Parsons Problems) -> 扩展已有功能 -> 从零编写函数的阶梯认知路线,极大降低 Day1-Day2 的心理摩擦。
- 测试验证演进路线:Day1 统一采用单文件内嵌 assert 自测模板(零依赖、运行即报错定位),Day2 下午平滑升级为独立 test_*.py 配合 pytest,帮助学生理解业务代码与测试代码解耦分离的工业界规范。
- 收尾项目结构规范化(借鉴 CS50P Final Project 黄金范式):收尾项目必须采用 CS50P 标准结构(
project.py包含main()与至少 3 个无外部副作用、参数化可测的纯函数 +test_project.py包含对应 pytest 断言 +README.md),使 3 小时的考核既可独立量化又具备严谨的工程感。 - 项目布局定调(Flat 布局 vs src 布局):3 天高中生短期培训严禁引入复杂的
src/包打包结构(避免引入sys.path查找与可编辑安装的认知包袱);应直接使用单层 Flat 扁平布局(项目根目录下project.py、test_project.py、pyproject.toml、.python-version),配合uv run python project.py运行。 - Python 3.14 与现代化工具兼容性:Python 3.14.4 下 pytest (8.4.2+)、Ruff (v0.15.x+) 与 Rich 已获得完整官方兼容;Ruff 原生支持 Python 3.14 的 PEP 758(无需括号的多异常捕获
except ValueError, KeyError:)与 PEP 649 延迟注解,执行速度极快,是初学者唯一的 Lint + Format 最佳工具。 - uv 命令行工作流闭环:教学全程使用声明式命令:
uv init --no-package初始化扁平项目、uv add rich演示依赖安装、uv add --dev pytest ruff安装测试工具、uv run pytest -q运行轻量测试、uv run ruff check ./uv run ruff format .培养规范的代码洁癖。 - 3 小时收尾项目可行边界:高中生 3 小时最佳候选为 CLI 待办/记账管理器(JSON 增删查改)或 Wordle/猜词游戏(CLI 状态机与 ANSI 彩色渲染),业务核心逻辑严格控制在 120-160 行代码、3-4 个纯函数,预留 40 分钟专门编写 5-8 个 pytest 测试与项目 README。
二、 经典练习题库参考与练习设计模式¶
1. Harvard CS50P 各周 Problem Set 题库全景分析¶
Harvard CS50P(CS50 Introduction to Programming with Python)是全球最经典的 Python 入门实践课程,其 Problem Set 以场景生动、规范明确、可自动评测著称:
| 周次 / 主题 | 题目名称 | 考察核心知识点 | 认知难度 | 题型与出题风格特色 |
|---|---|---|---|---|
| Week 0 Functions & Variables |
Indoor VoicePlayback SpeedMaking FacesEinsteinTip Calculator |
字符串小写化 (lower())、替换 (replace())、类型转换 (int/float)、质能方程计算、f-string 格式化 |
★☆☆☆☆ 入门 | 输入输出单映射,简明单一的数学/文本转换,建立基本 I/O 信心 |
| Week 1 Conditionals |
Deep ThoughtHome Federal Savings BankFile ExtensionsMath InterpreterMeal Time |
多分支 if/elif/else、前缀匹配 (startswith())、strip() 清理、字符串分割与浮点时间范围转换 |
★★☆☆☆ 基础 | 模拟真实生活规则判断(如银行打招呼奖励、餐点时间窗口、文件扩展名 MIME 解析) |
| Week 2 Loops |
camelCaseCoke MachineJust setting up my twttrVanity PlatesNutrition Facts |
for/while 循环、字符串遍历过滤、累加器模式、车牌规则多重校验、字典键值匹配查找 |
★★☆☆☆ 进阶 | 经典业务逻辑校验(如自动售货机硬币累加找零、剔除元音字母、驼峰与下划线互转) |
| Week 3 Exceptions |
Fuel GaugeFelipe TaqueriaGrocery ListOutdated |
try/except 捕获 ValueError / ZeroDivisionError、EOFError (Ctrl+D 结束输入)、多格式日期解析 |
★★★☆☆ 中等 | 防御性编程:用户输入不合法时提示并反复重试,直到输入正确,建立健壮性意识 |
| Week 4 Libraries |
EmojizeFrank, Ian and Glen LettersAdieu, AdieuGuessing GameLittle ProfessorBitcoin Price Index |
random 随机模块、sys.argv 命令行参数、requests 调用外部 REST API 解析 JSON、第三方库整合 |
★★★☆☆ 中等 | 走出纯控制台,结合标准库与外部 API,让程序连接现实世界(如实时比特币价格查询) |
| Week 5 Unit Tests |
Testing my twttrBack to the BankRe-requesting a Vanity PlateRefueling |
pytest 编写、重构已有函数为纯函数 (return 代替 print)、边界测试与异常断言 (pytest.raises) |
★★★☆☆ 中等 | 单元测试专题:要求将之前写过的功能拆解为独立模块,编写独立断言测试用例集 |
| Week 6 File I/O |
Lines of CodePizza PyScourgifyCS50 P-Shirt |
文件打开与上下文管理 (with open)、csv.reader/DictReader、CSV 重构清洗、PIL 图像叠加 |
★★★☆☆ 中等 | 批处理管道:读取原始脏数据文件,清洗并转换,输出结构化新文件 |
| Week 7 Regular Expressions |
NUMB3RSWatch on YouTubeWorking 9 to 5Regular, um, ExpressionsResponse Validation |
re.search / re.sub、正则分组捕获、IP 地址/时间段格式验证、HTML iframe 提取 |
★★★★☆ 挑战 | 高级文本解析与合法性规则引擎(集训中可选择性降阶为字符串内置方法) |
| Week 8 OOP |
Seasons of LoveCookie JarCS50 Shirtificate |
自定义类 (class)、属性保护 (@property/getter/setter)、魔术方法 (__str__, __add__)、容量越界抛错 |
★★★★☆ 挑战 | 面向对象建模:封装实体状态与业务约束(如饼干罐容量上限溢出检查与存取操作) |
2. Exercism Python Track 核心概念练习对照表¶
Exercism Python 概念树(Concept Tree)设计非常适合用于制定循序渐进的知识点练习:
| 题目名称 (Exercise Name) | 对应核心语言概念 (Concepts) | 教学目标与练习设计启示 |
|---|---|---|
Guido Gorgeous Lasagna |
Basics (变量、常量、函数定义、文档注释) | 定义常量 EXPECTED_BAKE_TIME,实现基于时间的加减计算与文档说明 |
Currency Exchange |
Numbers (整数、浮点数、取模 // 与 %) |
货币兑换计算、手续费扣除、找零面额整除计算 |
Ghost Gobble Arcade Game |
Booleans (布尔逻辑与短路运算 and/or/not) |
经典吃豆人(Pacman)状态机规则判断(吃豆、被吃、获胜条件) |
Meltdown Mitigation |
Conditionals (比较操作符、多分支阈值划分) | 核反应堆温度/中子临界状态监控与控制警报分类 |
Black Jack |
Comparisons & Conditionals (多条件评估) | 21 点纸牌分值计算、比大小及拆牌决策模型 |
Little Sister Vocabulary |
Strings (字符串切片、前缀/后缀操作、join()) |
构词法自动化:前缀加 un-、后缀加 -en、提取词根 |
Card Games |
Lists (列表索引、切片、追加、均值计算) | 纸牌游戏中的列表基本操作、首尾交换、奇偶数牌提取 |
Chaitana Colossal Coaster |
List Methods (append, insert, remove, pop) |
游乐园过山车排队系统:VIP 插队、离队、排队顺序查询 |
Making the Grade |
Loops (for, while, enumerate, 累加与过滤) |
学生考试成绩统计:及格率统计、前 4 名成绩提取、等级划分 |
Tisbury Treasure Hunt |
Tuples (元组组合、解包、坐标与线索匹配) | 寻宝游戏:将藏宝图坐标 (char, int) 与藏宝地点记录合并为扩展元组 |
Inventory Management |
Dicts (字典增删改查、get() 默认值、频次统计) |
RPG 仓库系统:战利品拾取计数、消耗品扣减、清空零库存 |
Cater-Waiter |
Sets (集合去重、交集 &、差集 -、子集判断) |
宴会菜单系统:过敏源交集检测、全素宴匹配、菜系成分去重 |
Locomotive Engineer |
Unpacking & Multiple Assignment (*args, **kwargs) |
火车车厢重组:利用 * 列表拆包、动态参数打包与字典合并 ** |
Ellen Alien Game |
Classes & OOP (属性初始化 __init__、方法、类属性) |
坐标空间外星人实体:生命值扣减、移动 (move)、存活状态判定 |
Mecha Munch Management |
Dict Methods (items(), update(), 字典推导) |
自动化购物车订购与库存管理调度系统 |
3. Codewars 8kyu / 7kyu 经典入门题清单¶
Even or Odd(8kyu - 基础分支):判断整数奇偶性,考察最基础的取模 % 2 与分支返回。Reversed Strings(8kyu - 字符串):反转字符串,考察切片s[::-1]或reversed()。Sum of Positive(8kyu - 列表与过滤):求列表中所有正数的和,考察遍历累加或一行推导sum(x for x in nums if x > 0)。Vowel Count(7kyu - 计数与容器):统计字符串中元音字母 a, e, i, o, u 的数量,考察char in [a, e, i, o, u]与循环计数。List Filtering(7kyu - 列表类型检查):过滤掉列表中的字符串,仅保留非负整数,考察isinstance(x, int)。Jenny Secret Message(8kyu - Debug 找错):函数在 if 之前写了无条件 return 导致分支失效,训练阅读代码与控制流纠错。Sentence Smash(8kyu - 字符串拼接):将单词列表拼接为完整句子,考察join(words)与空列表边界。Highest and Lowest(7kyu - 字符串转换与极值):输入空格分隔的数字字符串,返回最高和最低分,考察 split()、map(int, ...)、max() 与 min()。Get the Middle Character(7kyu - 索引与数学计算):返回单词的中间字符(偶数字长返回中间 2 个,奇数返回 1 个),考察整数除法与切片边界。Opposite Number/Return Negative(8kyu - 基础运算与负数):符号转换与绝对值边界处理。
4. 六种练习设计模式(含 Python 示例)¶
在 3 天集训中,必须混合使用以下 6 种模式降低认知疲倦感:
模式 1:Parsons Problems(代码乱序重排)¶
适用阶段:Day1 循环与分支引入期。专注逻辑控制流与缩进,无需敲语法细节。
# 【练习:Parsons Problem 乱序重排】
# 任务:将以下打乱顺序的代码行(A-G)按正确缩进和顺序重排,实现统计列表中正数平均值的功能。
# 待重排代码片段:
# [A] total += x
# [B] if count == 0: return 0.0
# [C] for x in numbers:
# [D] if x > 0:
# [E] return total / count
# [F] total, count = 0, 0
# [G] count += 1
# --- 请在下方写出重排后的正确代码 ---
def calculate_positive_average(numbers: list[int]) -> float:
total, count = 0, 0
for x in numbers:
if x > 0:
total += x
count += 1
if count == 0:
return 0.0
return total / count
模式 2:Fill-in-the-Blank(完形填空)¶
适用阶段:Day1 数据结构与 Day2 文件操作。保留主干,填补关键参数或方法。
# 【练习:Fill-in-the-Blank 完形填空】
# 任务:补全下划线 ___ 处的代码,实现安全读取 CSV 第一列姓名的功能。
import csv
def extract_names(csv_filepath: str) -> list[str]:
names = []
# 1. 以只读模式安全打开文件
with open(csv_filepath, mode='r', encoding='utf-8') as f:
reader = csv.reader(f)
# 跳过表头
next(reader)
for row in reader:
if row: # 过滤非空行
names.append(row[0]) # 取第一列
return names
模式 3:Debugging Exercises(找 Bug 纠错)¶
适用阶段:Day1 函数与可变对象陷阱、Day2 异常处理。
# 【练习:找 Bug(修复 2 处逻辑缺陷)】
# 缺陷 1:默认参数使用了可变列表,导致多次调用间数据污染;
# 缺陷 2:没有检查打折率是否在 0.0 ~ 1.0 之间。
def apply_discount(price: float, rate: float = 0.1, history: list[float] | None = None) -> float:
if history is None:
history = []
if not (0.0 <= rate <= 1.0):
raise ValueError('折扣率必须在 0.0 到 1.0 之间')
final_price = round(price * (1 - rate), 2)
history.append(final_price)
return final_price
模式 4:Predict Output(读代码预测输出)¶
适用阶段:Day1 作用域、列表浅拷贝/可变性;Day2 面向对象与推导式。
# 【练习:读代码写输出】请在不运行 Python 的情况下写出下列 print 的输出结果:
a = [1, 2, [3, 4]]
b = a.copy()
b[0] = 99
b[2].append(5)
print(a[0]) # 预测输出:1 (浅拷贝基础层独立)
print(a[2]) # 预测输出:[3, 4, 5] (嵌套列表共享引用)
print(a == b) # 预测输出:False
模式 5:Write from Scratch(从零实现指定接口)¶
适用阶段:核心函数训练(如密码强度检测器、回文检测)。
def check_password_strength(password: str) -> bool:
# 强密码规则:长度至少 8 位,且包含大写、小写与数字
if len(password) < 8:
return False
has_upper = any(c.isupper() for c in password)
has_lower = any(c.islower() for c in password)
has_digit = any(c.isdigit() for c in password)
return has_upper and has_lower and has_digit
模式 6:Extend Existing Program(扩展已有程序)¶
适用阶段:Day2 面向对象与收尾项目前置演练。
class BankAccount:
def __init__(self, owner: str, balance: float = 0.0):
self.owner = owner
self.balance = balance
def deposit(self, amount: float) -> float:
if amount <= 0:
raise ValueError('存款金额必须大于 0')
self.balance += amount
return self.balance
# --- 学生需要扩展的代码 ---
class SavingsAccount(BankAccount):
def __init__(self, owner: str, balance: float = 0.0, annual_rate: float = 0.03):
super().__init__(owner, balance)
self.annual_rate = annual_rate
def apply_interest(self) -> float:
interest = self.balance * self.annual_rate
self.balance += interest
return self.balance
三、 三个收尾候选项目规格标准(Day3 / 3 小时专项)¶
借鉴 CS50P Final Project 验收规范:项目主程序为 project.py(含 main() 与 3 个以上无外部副作用的可测试纯函数),单元测试为 test_project.py,配备极简说明文档 README.md。
候选项目 1:命令行个人记账 / 待办管理器 (expense_tracker / todo_manager)¶
- 项目定位:经典 CRUD 工具,强固化字典/列表、JSON 持久化与异常处理。
- 3 小时可行范围(Core MVP):
- 终端循环交互菜单(1. 记录 2. 查阅 3. 统计 4. 删除/标记 5. 退出)。
- 单一数据存储于本地
data.json。 - 核心功能清单(5-8 条):
add_item(items: list[dict], title: str, amount: float, category: str) -> dict: 创建新条目并追加到列表,返回新增条目字典。calculate_total(items: list[dict], category: str | None = None) -> float: 计算总支出(支持按分类过滤求和)。format_summary(items: list[dict]) -> str: 将所有账目格式化为整齐对齐的文本表格。save_to_json(items: list[dict], filepath: str) -> None: 安全写入 JSON 文件。load_from_json(filepath: str) -> list[dict]: 安全读取 JSON 文件(文件不存在时自动返回空列表,防止崩溃)。delete_item_by_id(items: list[dict], item_id: int) -> bool: 按编号删除条目,成功返回 True,不存在返回 False。- 进阶可选扩展(3 条):
- 使用
rich.table渲染彩色终端表格。 - 增加月份筛选过滤功能(基于
datetime.date字符串)。 - 增加预算超支红色预警功能。
- 覆盖知识点:列表嵌套字典、
json模块 (dump/load)、try/except FileNotFoundError、字符串格式化、pytest针对纯函数的独立断言。 - 验收标准:
project.py中至少有 3 个与 I/O 隔离的纯函数在test_project.py中有完整断言。data.json损坏或为空时程序不崩溃且能正常恢复。ruff check .零警告。- 成熟参考资源:
- Real Python - Build a Command-Line To-Do App with Python (
https://realpython.com/python-todo-list-cli/) - CS50P Gallery - Personal Task Manager (
https://cs50.harvard.edu/python/gallery)
候选项目 2:CLI 猜词游戏 / 终端版 Wordle 克隆 (wordle_cli)¶
- 项目定位:状态机与算法逻辑类游戏,强化字符串分析、随机模块与交互反馈。
- 3 小时可行范围(Core MVP):
- 预设/文件读取 5 字母词库,6 次猜词机会,终端给出每一位的匹配状态(绿色=完全命中,黄色=位置不对,灰色=不存在)。
- 核心功能清单(5-8 条):
evaluate_guess(secret: str, guess: str) -> list[str]: 核心判定算法(输入 target 与 guess,精确返回如['G', 'Y', 'X', 'G', 'X']状态列表,需正确处理重复字母边缘情况)。is_valid_word(word: str, word_list: set[str]) -> bool: 校验输入是否为有效的 5 字母且在词库中的合法词汇。render_feedback(guess: str, status: list[str]) -> str: 将猜词状态转换为 ANSI 彩色字符串或 Emoji 方块字符串。update_stats(stats: dict, won: bool, attempts: int) -> dict: 更新连胜场次、总局数、猜测次数分布统计字典。save_stats_file(stats: dict, filepath: str) -> None: 将胜率战绩持久化保存至本地 JSON。- 进阶可选扩展(3 条):
- 引入
random.choice从外部words.txt文件随机加载秘密单词。 - 增加未猜字母的剩余可用字母盘(A-Z 状态追踪)。
- 增加困难模式(Hard Mode):后续猜测必须包含之前已发现的线索字母。
- 覆盖知识点:字符串遍历与切片、集合成员查找 (
in set)、random模块、字典统计逻辑、算法边界条件测试(多重复字母判定)。 - 验收标准:
evaluate_guess函数测试覆盖 4 种以上不同用例(全对、全错、含重复字母等)。- 游戏具备循环重玩机制,输入非 5 字母时不消耗猜词步数且友好提示。
- 成熟参考资源:
- Real Python - Build a Wordle Clone in Python (
https://realpython.com/python-wordle-clone/) - CS50P Gallery - Wordle Game CLI (
https://cs50.harvard.edu/python/gallery)
候选项目 3:CSV 成绩与数据分析小工具 (grade_analyzer)¶
- 项目定位:数据处理与自动化报告生成管道,强化文件流、数据聚合与数学统计。
- 3 小时可行范围(Core MVP):
- 读取班级学生各科成绩的 CSV 文件,完成及格率、平均分、排名计算,并在终端打印统计报告并导出新的汇总 CSV。
- 核心功能清单(5-8 条):
parse_grade_record(raw_row: dict) -> dict: 数据清洗函数,将 CSV 读取到的字符串分数转换为 float,无效值设为默认 0.0。calculate_subject_stats(scores: list[float]) -> dict: 利用statistics模块计算平均分、中位数、最高分、最低分与标准差。assign_grade_letter(score: float) -> str: 按分数段划分等级(A: >=90, B: >=80, C: >=70, D: >=60, F: <60)。aggregate_by_class(records: list[dict]) -> dict[str, list[dict]]: 依据班级字段将所有学生记录分组聚合。generate_ranked_report(records: list[dict]) -> list[dict]: 按总分从高到低对学生排序并添加名次字段rank。export_summary_csv(summary_data: list[dict], output_filepath: str) -> None: 将统计汇总结果写入新 CSV 文件。- 进阶可选扩展(3 条):
- 生成 ASCII 柱状直方图打印在终端(如
[90-100]: ******** (8人))。 - 异常输入容错(成绩出现负数或超过 100 时记录警告日志并跳过)。
- 支持自定义科目权重的综合绩点 (GPA) 计算。
- 覆盖知识点:
csv.DictReader/csv.DictWriter、statistics模块 (mean,median,stdev)、dict分组字典技巧、sorted(key=lambda ...)排序。 - 验收标准:
- 针对
calculate_subject_stats、assign_grade_letter、generate_ranked_report编写 pytest 参数化测试。 - 空文件或异常数据行不会导致程序崩溃。
- 成熟参考资源:
- Automate the Boring Stuff with Python - Working with CSV Files (
https://automatetheboringstuff.com/2e/chapter16/) - CS50P Problem Set 6 - Scourgify / Pizza Py (
https://cs50.harvard.edu/python/psets/6/)
四、 现代开发工具链最小可用指南(Python 3.14.4 + uv + pytest + ruff)¶
1. 项目结构决策:Flat 布局 vs src/ 布局¶
- 调研结论:高中生 3 天集训必须坚定采用 Flat(扁平)单层布局,严禁使用
src/布局。 - 原因分析:
uv init默认生成 app 骨架;但通过uv init --no-package生成的是纯净的扁平目录,没有src/pkg/__init__.py的多层路径嵌套。- 初学者在
src/布局下运行python script.py极易踩中ModuleNotFoundError(因工作目录未挂入PYTHONPATH),而单层 flat 布局让project.py和test_project.py处于同级,直接uv run pytest或uv run python project.py永远不会出现导入路径混乱。
推荐的标准项目结构¶
my-project/
├── .python-version # 内容为 3.14.4
├── pyproject.toml # 项目配置与依赖声明
├── project.py # 核心业务代码
├── test_project.py # pytest 测试用例
└── README.md # 项目说明文档
极简 pyproject.toml 模板¶
[project]
name = "my-project"
version = "0.1.0"
description = "High school 3-day training project"
readme = "README.md"
requires-python = ">=3.14"
dependencies = [
"rich>=13.9.0",
]
[dependency-groups]
dev = [
"pytest>=8.4.2",
"ruff>=0.15.0",
]
2. uv 常用操作命令与原理解析¶
| 目标操作 | 终端命令 | 说明与高中生易错点提示 |
|---|---|---|
| 初始化项目 | uv init --no-package |
在当前目录生成极简 flat 结构的 pyproject.toml 和 .python-version |
| 添加第三方库 | uv add rich |
自动下载并锁定 rich 依赖,写入 pyproject.toml |
| 添加开发测试工具 | uv add --dev pytest ruff |
将 pytest 与 ruff 加入 [dependency-groups] dev |
| 运行主程序 | uv run python project.py |
自动在当前隔离虚拟环境中运行(无需手动激活虚拟环境) |
| 直接运行 vs uv run | python project.py vs uv run ... |
直接 python 依赖全局环境,缺少隔离依赖时会报 ModuleNotFound;uv run 始终保障虚拟环境精确加载 |
| 一键格式化 | uv run ruff format . |
毫秒级自动修复缩进、空格与代码风格 |
| 一键代码检查 | uv run ruff check . --fix |
检查语法错误、未引用的变量并自动安全修复 |
| 运行单元测试 | uv run pytest -q |
-q (quiet) 极简输出模式,降低初学者的终端信息噪点 |
- 关于 Rich 的引入:Rich 是 Day2 演示第三方库的最佳示例,对 Python 3.14 具备完备支持,且通过 rich 库的彩色打印能即时给予学生直观的正反馈。
3. pytest 最小可用实践(Python 3.14 兼容)¶
- pytest 现状:当前 pytest 8.4.2+ / 9.x 已对 Python 3.14 提供完全支持。
- 测试文件命名规范:必须以
test_*.py命名,测试函数必须以def test_*():开头。 - 断言方式:直接使用原生
assert expr, "失败提示",无需复杂的断言类。 - 异常测试 (
pytest.raises) 与 参数化测试 (@pytest.mark.parametrize) 示范:
# test_project.py
import pytest
from project import calculate_total, assign_grade_letter, divide_funds
# 1. 常规断言
def test_calculate_total():
sample_data = [
{"item": "apple", "amount": 10.5},
{"item": "banana", "amount": 5.5},
]
assert calculate_total(sample_data) == 16.0
assert calculate_total([]) == 0.0
# 2. 参数化多用例测试
@pytest.mark.parametrize("score, expected_grade", [
(95.0, "A"),
(89.9, "B"),
(75.0, "C"),
(60.0, "D"),
(45.0, "F"),
])
def test_assign_grade_letter(score, expected_grade):
assert assign_grade_letter(score) == expected_grade
# 3. 异常捕获断言
def test_divide_funds_zero_division():
with pytest.raises(ValueError, match="人数不能为零或负数"):
divide_funds(total_money=100.0, people_count=0)
pytest 输出解读指南(向学生解释)¶
.(绿点):测试通过。F(红字 Failure):逻辑断言失败(预期与实际不符)。E(红字 Error):代码发生未捕获的意外崩溃(如 NameError、IndexError)。- 底部统计:
=== 3 passed in 0.05s ===。
4. Ruff 规则与 3.14 语法特性¶
- Ruff 现状:Ruff v0.15+ 完全支持 Python 3.14,包含 PEP 758(允许多异常捕获省略括号
except ValueError, KeyError:)。 - 极简配置(可选放于
pyproject.toml):
5. VS Code 运行测试配置(一句话)¶
VS Code Testing 配置要点:按
Ctrl+Shift+P输入并执行Python: Configure Tests,选择pytest并在目录中选择根目录.,左侧活动栏即可通过小烧杯图标(Testing 选项卡)一键点击运行与断点调试所有测试用例。
五、 练习模板规范示例¶
1. Day 1 零依赖 assert 自测练习文件模板 (exercise_day1_demo.py)¶
"""
【Day 1 练习】字符串与列表基础处理
要求:实现以下函数,直接运行本文件进行自测。
所有测试通过时会打印:恭喜!所有 assert 测试均已通过!
"""
# ==================== 学生作答区域 ====================
def format_full_name(first: str, last: str) -> str:
# TODO 1: 将名和姓拼接为大驼峰格式全名(去除首尾多余空格,首字母大写)
# 例如: format_full_name(' guido ', 'van Rossum ') -> 'Guido Van Rossum'
clean_first = first.strip().capitalize()
clean_last = last.strip().capitalize()
return f'{clean_first} {clean_last}'
def filter_even_squares(numbers: list[int]) -> list[int]:
# TODO 2: 提取列表中所有的偶数,并返回它们各自平方组成的列表
# 例如: filter_even_squares([1, 2, 3, 4, 5]) -> [4, 16]
return [x ** 2 for x in numbers if x % 2 == 0]
# ==================== 自动化断言自测区域 ====================
if __name__ == '__main__':
print('正在运行自测断言...')
# 1. 测试 format_full_name
assert format_full_name('alice', 'smith') == 'Alice Smith', '测试失败: 基本拼接错误'
assert format_full_name(' BOB ', ' LEE ') == 'Bob Lee', '测试失败: 空格去除或大小写转换错误'
assert format_full_name('john', '') == 'John ', '测试失败: 空字符串边界错误'
# 2. 测试 filter_even_squares
assert filter_even_squares([1, 2, 3, 4]) == [4, 16], '测试失败: 常规偶数平方提取错误'
assert filter_even_squares([1, 3, 5]) == [], '测试失败: 无偶数时应返回空列表'
assert filter_even_squares([]) == [], '测试失败: 输入空列表时应返回空列表'
print('恭喜!所有 assert 测试均已通过!代码正确无误!')
2. Day 2 进阶规范 pytest 测试文件模板 (test_exercise_day2.py)¶
配合学生编写的模块 solution_day2.py:
# test_exercise_day2.py
import pytest
from solution_day2 import parse_config_line, SafeBankVault
class TestConfigParser:
@pytest.mark.parametrize('line, expected_key, expected_val', [
('port=8080', 'port', '8080'),
(' host = 127.0.0.1 ', 'host', '127.0.0.1'),
('debug = true', 'debug', 'true'),
])
def test_parse_valid_lines(self, line, expected_key, expected_val):
key, val = parse_config_line(line)
assert key == expected_key
assert val == expected_val
def test_parse_invalid_line_raises_value_error(self):
with pytest.raises(ValueError, match='无效的配置行格式'):
parse_config_line('invalid_line_without_equal_sign')
class TestSafeBankVault:
def test_deposit_and_withdraw(self):
vault = SafeBankVault(initial_balance=100.0)
vault.deposit(50.0)
assert vault.balance == 150.0
vault.withdraw(30.0)
assert vault.balance == 120.0
def test_withdraw_insufficient_funds_raises(self):
vault = SafeBankVault(initial_balance=50.0)
with pytest.raises(RuntimeError, match='余额不足'):
vault.withdraw(100.0)
六、 调研真实来源与参考列表¶
- Harvard CS50P (CS50 Introduction to Programming with Python):
- Problem Sets 0-8 官方主页:
https://cs50.harvard.edu/python/psets/(访问日期: 2026-09-05) - Final Project Specification 规范:
https://cs50.harvard.edu/python/project/(访问日期: 2026-09-05) - Final Projects Showcase:
https://cs50.harvard.edu/python/gallery/(访问日期: 2026-09-05) - Exercism Python Syllabus & Concept Exercises:
- Python Track Concepts & Syllabus:
https://exercism.org/tracks/python/concepts(访问日期: 2026-09-05) - Official GitHub Repository (exercism/python):
https://github.com/exercism/python(访问日期: 2026-09-05) - Codewars Python Practice Collection:
- Beginner Katas 8kyu & 7kyu Collection:
https://www.codewars.com/collections/python-beginner-katas-comprehensive(访问日期: 2026-09-05) - Astral uv Official Documentation:
- uv Projects & Initial Layout:
https://docs.astral.sh/uv/concepts/projects/init/(访问日期: 2026-09-05) - uv Configuration & Build Backends:
https://docs.astral.sh/uv/concepts/projects/config/(访问日期: 2026-09-05) - pytest Documentation & Release Notes:
- pytest Changelog & Python 3.14 compatibility:
https://docs.pytest.org/en/stable/changelog.html(访问日期: 2026-09-05) - pytest-dev GitHub Releases (8.4.2+):
https://github.com/pytest-dev/pytest/releases(访问日期: 2026-09-05) - Astral Ruff Documentation & Release Notes:
- Ruff v0.15+ Release & Python 3.14 Features (PEP 758):
https://astral.sh/blog/ruff-v0.15.0(访问日期: 2026-09-05) - Ruff GitHub Repository:
https://github.com/astral-sh/ruff(访问日期: 2026-09-05) - VS Code Python Testing Documentation:
- Python Testing in Visual Studio Code:
https://code.visualstudio.com/docs/python/testing(访问日期: 2026-09-05)