跳转至
Python 进阶手册 实战

综合项目

看懂和会用之间隔着大量的练习。下面 6 个项目按学习阶段排列,每个都覆盖了若干章节的知识点。每个项目都给出了需求、验收标准和提示,但没有给完整答案:卡住时回到对应章节找思路,这正是练习的意义。

做项目的方法

  • 先跑通,再做好。 第一版只实现最核心的功能,确认能用,再逐步加上错误处理、测试、类型标注。
  • 每个项目都用 uv 建成完整的工程:src 布局、ruff、mypy、pytest,参考项目与工具链。
  • 写完后自己做一次代码审查,对照惯用法与常见坑末尾的清单。
  • 做完"进阶挑战"才算真正掌握。 进阶挑战往往会暴露第一版设计里的问题,迫使你重构。

项目一:命令行记账本

阶段:一、核心语言 知识点:dataclass、Enum、pathlib、json、argparse、datetime、异常处理

一个记录个人收支的命令行工具,数据保存在 JSON 文件里。

$ ledger add -50 --category food --note "午饭"
$ ledger add 8000 --category salary
$ ledger list --month 2026-09
$ ledger report --month 2026-09
收入 8000.00 | 支出 50.00 | 结余 7950.00
food      50.00  100.0%

需求

  • add:金额(正数收入、负数支出)、分类、备注、日期(默认今天)
  • list:按月份、分类筛选,按日期排序
  • report:某月的收入、支出、结余,以及支出按分类的占比
  • delete ID:删除一条记录

验收标准

  • 金额用 Decimal 存储和计算,JSON 里存成字符串
  • 数据文件不存在时自动创建;文件损坏时给出清楚的错误信息,而不是打印一段 traceback
  • 分类用 Enum 或者可配置的列表,输入不存在的分类时报错并列出可选项
  • 核心逻辑(统计、筛选)和命令行、文件读写分开,并有测试

进阶挑战

  • 支持导出 CSV、从银行账单 CSV 导入
  • 把存储换成 sqlite3,要求命令行代码一行都不用改(提示:定义一个存储的 Protocol)

项目二:大日志文件分析器

阶段:一、核心语言 知识点:生成器管道、re、Counter、itertools、heapq、性能

分析 Nginx 访问日志(可以自己写一个脚本生成几百万行的测试数据)。

需求

  • 统计:总请求数、各状态码数量、访问最多的前 10 个 URL 和 IP、每分钟的请求数
  • 找出响应时间最慢的前 20 个请求
  • 支持 .gz 压缩的日志文件,支持同时分析多个文件
  • 支持按时间范围过滤

验收标准

  • 使用生成器管道处理,内存占用和文件大小无关(处理 1GB 的文件,内存不超过 100MB)
  • 格式错误的行不会让程序崩溃,最后报告跳过了多少行
  • 用 cProfile 找出最慢的环节并优化,记录优化前后的耗时

进阶挑战

  • 用 ProcessPoolExecutor 并行处理多个文件,再合并统计结果(Counter 支持相加)
  • 支持 tail -f 模式:实时追踪一个正在写入的日志文件,每 5 秒刷新一次统计

项目三:带缓存和重试的异步爬虫

阶段:三、并发 知识点:asyncio、TaskGroup、Semaphore、超时、装饰器、httpx

从一个起始 URL 开始,抓取同一个域名下的页面,提取标题和链接。

需求

  • 同时最多 N 个请求,每个请求有超时,失败时指数退避重试
  • 不重复抓取同一个 URL;限制最大深度和最大页面数
  • 遵守 robots.txt
  • 把结果保存为 JSON Lines(每行一个 JSON 对象)

验收标准

  • 重试逻辑写成一个异步装饰器 @retry(times=3, exceptions=(httpx.TransportError,))
  • 按 Ctrl+C 时能优雅退出:取消所有任务、保存已抓取的结果
  • 用本地的 http.server 或 mock 的传输层写测试,测试不访问真实网络

进阶挑战

  • 增加对每个域名的速率限制(每秒最多 K 个请求)
  • 支持断点续爬:重启后跳过已抓取的 URL

项目四:插件式任务调度器

阶段:二、三 知识点:__init_subclass__、Protocol、类型标注、threading 或 asyncio、logging

一个轻量的定时任务调度器,任务以插件的形式定义。

class CleanupTask(Task, name="cleanup", every="10m"):
    def run(self, ctx: Context) -> None:
        ...

需求

  • 定义 Task 子类时自动注册(__init_subclass__),支持 every="30s"/"10m"/"1h" 这样的间隔
  • 调度器按间隔运行任务,同一个任务上一次还没跑完时不重复启动
  • 任务失败时记录日志并按策略重试,不影响其他任务
  • 提供一个查看各任务状态(上次运行时间、耗时、是否成功)的命令

验收标准

  • mypy strict 模式无错误
  • 调度逻辑可以在测试中用"假时钟"驱动,不需要真的等待
  • 支持从某个目录自动加载插件模块(importlib)

进阶挑战

  • 支持 cron 表达式
  • 任务状态持久化到 SQLite,重启后恢复

项目五:迷你键值数据库

阶段:三、四 知识点:asyncio 网络编程、协议设计、持久化、测试、性能

实现一个类似简化版 Redis 的内存键值数据库,通过 TCP 提供服务。

$ nc localhost 7379
SET name amy
OK
GET name
amy
EXPIRE name 10
OK
INCR counter
1

需求

  • 用 asyncio.start_server 实现服务器,支持多个客户端同时连接
  • 命令:GET、SET、DEL、EXISTS、INCR、EXPIRE、TTL、KEYS pattern
  • 持久化:定期把数据快照写到磁盘(先写临时文件再原子地 rename),启动时加载
  • 提供一个 Python 客户端库,支持 async with Client(...) as c: await c.set("k", "v")

验收标准

  • 命令解析用 match 语句
  • 端到端测试:测试里启动服务器,用客户端库验证各命令
  • 能承受 1000 个并发连接(写一个压测脚本验证)

进阶挑战

  • 支持追加日志(AOF)持久化,崩溃后不丢数据
  • 支持发布订阅(SUBSCRIBE/PUBLISH)

项目六:发布一个自己的库

阶段:四、工程化 知识点:打包、文档、CI、语义化版本、类型标注

挑一个你在前面项目里写过的、有复用价值的模块(比如重试装饰器、日志解析器、配置加载器),把它发布成一个真正的库。

需求

  • 完整的 pyproject.toml,支持 Python 3.12 及以上
  • 公开 API 有完整的类型标注,并附带 py.typed 标记文件
  • README 包含安装、快速开始、API 说明
  • GitHub Actions:在多个 Python 版本上跑 ruff、mypy、pytest;打标签时自动发布
  • 用 MkDocs 写一个文档站点(就像你正在看的这个)

验收标准

  • 在一个全新的虚拟环境里 uv add 你的库 后,按 README 能直接用起来
  • 测试覆盖率 90% 以上
  • 版本号遵循语义化版本,维护 CHANGELOG

进阶挑战

  • 先发布到 TestPyPI 验证流程,再发布到正式的 PyPI
  • 请朋友用一用,根据反馈发布 0.2.0

本章练习题(1 道)

在浏览器里直接写代码、跑测试;也可以在本地用 python practice/judge.py 判题。

发现错误或有更好的写法?在 GitHub 上编辑此页提交问题