跳转至

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


一、 核心结论(面向计划编写者的可执行要点)

  1. 练习组织递进原则(Scaffolding 渐进式支架):高中生在短时间内吸收大量概念,练习设计必须打破单一的从零手写,严格遵循读代码预测输出 -> 找 Bug(1-2行修复) -> 填空(Fill-in-the-blank) -> 乱序重排(Parsons Problems) -> 扩展已有功能 -> 从零编写函数的阶梯认知路线,极大降低 Day1-Day2 的心理摩擦。
  2. 测试验证演进路线:Day1 统一采用单文件内嵌 assert 自测模板(零依赖、运行即报错定位),Day2 下午平滑升级为独立 test_*.py 配合 pytest,帮助学生理解业务代码与测试代码解耦分离的工业界规范。
  3. 收尾项目结构规范化(借鉴 CS50P Final Project 黄金范式):收尾项目必须采用 CS50P 标准结构(project.py 包含 main() 与至少 3 个无外部副作用、参数化可测的纯函数 + test_project.py 包含对应 pytest 断言 + README.md),使 3 小时的考核既可独立量化又具备严谨的工程感。
  4. 项目布局定调(Flat 布局 vs src 布局):3 天高中生短期培训严禁引入复杂的 src/ 包打包结构(避免引入 sys.path 查找与可编辑安装的认知包袱);应直接使用单层 Flat 扁平布局(项目根目录下 project.pytest_project.pypyproject.toml.python-version),配合 uv run python project.py 运行。
  5. 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 最佳工具。
  6. 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 . 培养规范的代码洁癖。
  7. 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 Voice
Playback Speed
Making Faces
Einstein
Tip Calculator
字符串小写化 (lower())、替换 (replace())、类型转换 (int/float)、质能方程计算、f-string 格式化 ★☆☆☆☆ 入门 输入输出单映射,简明单一的数学/文本转换,建立基本 I/O 信心
Week 1
Conditionals
Deep Thought
Home Federal Savings Bank
File Extensions
Math Interpreter
Meal Time
多分支 if/elif/else、前缀匹配 (startswith())、strip() 清理、字符串分割与浮点时间范围转换 ★★☆☆☆ 基础 模拟真实生活规则判断(如银行打招呼奖励、餐点时间窗口、文件扩展名 MIME 解析)
Week 2
Loops
camelCase
Coke Machine
Just setting up my twttr
Vanity Plates
Nutrition Facts
for/while 循环、字符串遍历过滤、累加器模式、车牌规则多重校验、字典键值匹配查找 ★★☆☆☆ 进阶 经典业务逻辑校验(如自动售货机硬币累加找零、剔除元音字母、驼峰与下划线互转)
Week 3
Exceptions
Fuel Gauge
Felipe Taqueria
Grocery List
Outdated
try/except 捕获 ValueError / ZeroDivisionErrorEOFError (Ctrl+D 结束输入)、多格式日期解析 ★★★☆☆ 中等 防御性编程:用户输入不合法时提示并反复重试,直到输入正确,建立健壮性意识
Week 4
Libraries
Emojize
Frank, Ian and Glen Letters
Adieu, Adieu
Guessing Game
Little Professor
Bitcoin Price Index
random 随机模块、sys.argv 命令行参数、requests 调用外部 REST API 解析 JSON、第三方库整合 ★★★☆☆ 中等 走出纯控制台,结合标准库与外部 API,让程序连接现实世界(如实时比特币价格查询)
Week 5
Unit Tests
Testing my twttr
Back to the Bank
Re-requesting a Vanity Plate
Refueling
pytest 编写、重构已有函数为纯函数 (return 代替 print)、边界测试与异常断言 (pytest.raises) ★★★☆☆ 中等 单元测试专题:要求将之前写过的功能拆解为独立模块,编写独立断言测试用例集
Week 6
File I/O
Lines of Code
Pizza Py
Scourgify
CS50 P-Shirt
文件打开与上下文管理 (with open)、csv.reader/DictReader、CSV 重构清洗、PIL 图像叠加 ★★★☆☆ 中等 批处理管道:读取原始脏数据文件,清洗并转换,输出结构化新文件
Week 7
Regular Expressions
NUMB3RS
Watch on YouTube
Working 9 to 5
Regular, um, Expressions
Response Validation
re.search / re.sub、正则分组捕获、IP 地址/时间段格式验证、HTML iframe 提取 ★★★★☆ 挑战 高级文本解析与合法性规则引擎(集训中可选择性降阶为字符串内置方法)
Week 8
OOP
Seasons of Love
Cookie Jar
CS50 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 经典入门题清单

  1. Even or Odd (8kyu - 基础分支):判断整数奇偶性,考察最基础的取模 % 2 与分支返回。
  2. Reversed Strings (8kyu - 字符串):反转字符串,考察切片 s[::-1]reversed()
  3. Sum of Positive (8kyu - 列表与过滤):求列表中所有正数的和,考察遍历累加或一行推导 sum(x for x in nums if x > 0)
  4. Vowel Count (7kyu - 计数与容器):统计字符串中元音字母 a, e, i, o, u 的数量,考察 char in [a, e, i, o, u] 与循环计数。
  5. List Filtering (7kyu - 列表类型检查):过滤掉列表中的字符串,仅保留非负整数,考察 isinstance(x, int)
  6. Jenny Secret Message (8kyu - Debug 找错):函数在 if 之前写了无条件 return 导致分支失效,训练阅读代码与控制流纠错。
  7. Sentence Smash (8kyu - 字符串拼接):将单词列表拼接为完整句子,考察 join(words) 与空列表边界。
  8. Highest and Lowest (7kyu - 字符串转换与极值):输入空格分隔的数字字符串,返回最高和最低分,考察 split()、map(int, ...)、max() 与 min()。
  9. Get the Middle Character (7kyu - 索引与数学计算):返回单词的中间字符(偶数字长返回中间 2 个,奇数返回 1 个),考察整数除法与切片边界。
  10. 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.DictWriterstatistics 模块 (mean, median, stdev)、dict 分组字典技巧、sorted(key=lambda ...) 排序。
  • 验收标准
  • 针对 calculate_subject_statsassign_grade_lettergenerate_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.pytest_project.py 处于同级,直接 uv run pytestuv 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
    [tool.ruff]
    line-length = 88
    target-version = "py314"
    
    [tool.ruff.lint]
    select = ["E", "F", "I"] # 基础语法、未定义变量、未引用导入自动整理
    

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)

六、 调研真实来源与参考列表

  1. Harvard CS50P (CS50 Introduction to Programming with Python):
  2. Problem Sets 0-8 官方主页: https://cs50.harvard.edu/python/psets/ (访问日期: 2026-09-05)
  3. Final Project Specification 规范: https://cs50.harvard.edu/python/project/ (访问日期: 2026-09-05)
  4. Final Projects Showcase: https://cs50.harvard.edu/python/gallery/ (访问日期: 2026-09-05)
  5. Exercism Python Syllabus & Concept Exercises:
  6. Python Track Concepts & Syllabus: https://exercism.org/tracks/python/concepts (访问日期: 2026-09-05)
  7. Official GitHub Repository (exercism/python): https://github.com/exercism/python (访问日期: 2026-09-05)
  8. Codewars Python Practice Collection:
  9. Beginner Katas 8kyu & 7kyu Collection: https://www.codewars.com/collections/python-beginner-katas-comprehensive (访问日期: 2026-09-05)
  10. Astral uv Official Documentation:
  11. uv Projects & Initial Layout: https://docs.astral.sh/uv/concepts/projects/init/ (访问日期: 2026-09-05)
  12. uv Configuration & Build Backends: https://docs.astral.sh/uv/concepts/projects/config/ (访问日期: 2026-09-05)
  13. pytest Documentation & Release Notes:
  14. pytest Changelog & Python 3.14 compatibility: https://docs.pytest.org/en/stable/changelog.html (访问日期: 2026-09-05)
  15. pytest-dev GitHub Releases (8.4.2+): https://github.com/pytest-dev/pytest/releases (访问日期: 2026-09-05)
  16. Astral Ruff Documentation & Release Notes:
  17. Ruff v0.15+ Release & Python 3.14 Features (PEP 758): https://astral.sh/blog/ruff-v0.15.0 (访问日期: 2026-09-05)
  18. Ruff GitHub Repository: https://github.com/astral-sh/ruff (访问日期: 2026-09-05)
  19. VS Code Python Testing Documentation:
  20. Python Testing in Visual Studio Code: https://code.visualstudio.com/docs/python/testing (访问日期: 2026-09-05)