《Python编程入门》18.1 从零构建一个完整项目
把全书串起来做一个真项目:用 src 布局、pyproject.toml 与模块划分,从零构建命令行日志分析器 loglens,覆盖 dataclass 数据模型、正则解析、Counter 统计、argparse 入口与 pytest 测试,并真实跑通 pytest、ruff、mypy 与端到端 CLI。
tag
把全书串起来做一个真项目:用 src 布局、pyproject.toml 与模块划分,从零构建命令行日志分析器 loglens,覆盖 dataclass 数据模型、正则解析、Counter 统计、argparse 入口与 pytest 测试,并真实跑通 pytest、ruff、mypy 与端到端 CLI。
把 pandas 与 polars 放在一起讲:用同一份 50 万行销售数据各跑一遍 groupby 聚合,对比代码量与实测耗时,再实测 dtype 与内存占用、链式调用与惰性 API、apply 与向量化的性能差,并说清缺失值、NaN 与链式赋值的坑。
从合规边界讲起:用 urllib.robotparser 解析 robots.txt、遵守服务条款与请求频率,再在本地 http.server 上真抓真解析,掌握 httpx 状态码与编码处理、BeautifulSoup 的 find 与 select、分页限速与指数退避,以及动态渲染与存储去重。
用 pathlib 与 shutil 把散落的文件批量重命名、按扩展名归类、安全删除,掌握 zipfile/tarfile 的解压炸弹与路径穿越防护,再用 openpyxl 读写带公式与样式的 Excel,最后用 subprocess 与轮询式监听接进日常工作流。
把 Pydantic 校验、FastAPI 依赖注入与 SQLAlchemy 2.x 数据库访问拼成一个真实后端:Field 约束与自定义校验器、带 yield 的依赖做资源清理、select() 2.0 风格 CRUD 真跑 SQLite,并讲清 ORM 模型与 Pydantic 模型为何分离。
用 FastAPI 写下第一个真实可跑的 API:路径参数、查询参数、Pydantic 请求体、response_model、HTTPException、BackgroundTasks、APIRouter 与 Depends,看它自动生成的 OpenAPI 文档,并用 TestClient 写测试;最后实测 def 与 async def 端点的线程差异。
从一次真实的 HTTP 交互出发,看懂请求行、状态码、响应头与消息体;再分别手写最小 WSGI 应用(wsgiref)与最小 ASGI 应用(uvicorn)并真跑起来,对照 environ 与 scope 结构,理解同步阻塞模型与事件循环模型的根本差异。
锁定依赖是可复现构建的地基。本节先拆 pip freeze 为何不可复现,再对比 uv/poetry/pdm/pip-tools 的锁文件分工,用 packaging 与 pip 实测 diamond dependency 冲突,演示 require-hashes 哈希校验与离线安装,最后落到容器镜像中的可复现要点。
构建产物 sdist 与 wheel 到底差在哪?本节逐段解码 wheel 文件名,真实跑一次 python -m build,把 wheel 装进临时 venv 执行 console_scripts 命令,再讲清包数据、入口点插件、twine check、TestPyPI 与 PyPI 的上传流程,以及版本号不可复用这条硬规则。
从 setup.py 与 requirements.txt 的历史包袱讲起,用 PEP 518/517/621 三条线串起 pyproject.toml 的来历;拆解 build-system 后端选型与 project 表标准字段,重点实测依赖说明符中 ~= 的锁定边界与逗号、空格的区别,并给出经 tomllib 校验的完整配置。
从 pytest-cov 的实跑报告讲起,说明 100% 行覆盖不等于测到边界,用 --cov-branch 对比数字;再实跑 ruff check/format 与 mypy --strict,给出 pyproject 配置段,最后落到 pre-commit 与 GitHub Actions,把质量门禁分成本地、CI、发布前三层。
把测试从单条函数升级为可复用、可组合的工程:讲清 fixture 的参数注入与四种作用域、yield 拆解、conftest.py 层级发现、tmp_path 与 monkeypatch,再用 parametrize 和 unittest.mock 演示 patch 该打在哪一层、autospec 与 call_args 怎么用。
从 unittest 的写法对比切入 pytest:讲清 test_ 前缀的自动发现规则、assert 断言重写为何能给出逐元素 diff、pytest.raises 与 match、pytest.approx 浮点比较、skip/skipif/xfail 三种标记,以及 src 布局、pyproject 配置与 -v/-k/-x/--lf 常用开关。
同步库直接写进 async 会阻塞整个事件循环。本节用本地服务实测 requests 串行、to_thread 与 httpx.AsyncClient 的耗时差,讲连接池、contextvars、async for 与 async with,并盘点假异步:忘记 await、循环里串行 await、create_task 丢引用,最后说明何时不该用异步。
create_task 立刻调度、gather 要 await 才跑。本节对比 gather 与 TaskGroup 的错误处理:gather 不取消兄弟任务,TaskGroup 会取消并用 ExceptionGroup 汇总;再讲 asyncio.timeout、shield、CancelledError 的 BaseException 语义、Queue、Semaphore 与 Runner。
协程函数调用后只返回一个协程对象,不 await 就静默不执行。本节从 async def 与 await 的语义讲起,用真实计时证明单线程并发,再用 time.sleep 与 asyncio.sleep 的对比说明阻塞调用如何卡死事件循环,并厘清 get_running_loop 与 get_event_loop 的差异。
从 TCP/IP 分层讲起,用 socket 手写能跑通的 echo server/client,理解 bind/listen/accept/connect/send/recv、粘包与分帧、settimeout;再用原始 socket 看清 HTTP 请求行长什么样,对比 urllib、requests 会话复用与 httpx 同步/异步双接口。
线程池与进程池共享同一套 concurrent.futures 接口:submit 返回 Future、map 保序、as_completed 抢先返回,异常要调用 result() 才抛出。本节实测进程池的 __main__ 守卫报错、小任务反转、chunksize 与启动开销,并讲清进程间共享数据。
GIL 让同一时刻只有一个线程执行 Python 字节码。本节讲清它保护什么、为何存在,用真实计时证明 CPU 密集多线程不提速而 IO 密集近线性提速,再讲透 Thread/Lock/Event/Semaphore/Queue、竞态复现与线程进程选型。
sys.argv 太原始,argparse 是标准库自带的命令行解析方案。本节覆盖位置与可选参数、type 与 choices、nargs、store_true/count/append、子命令、FileType、parse_known_args 与退出码,并给出 __main__ 守卫组织方式,每个示例都真实运行。