前沿与实践 · Frontier & Practice
lv.4 前沿
kp-045
工程规范与代码质量
1. 一句话定义
现代 Python 工程质量的"三件套":ruff(极快 linter + formatter,取代 black/isort/flake8)、类型检查(mypy/pyright,kp-026)、pre-commit(提交前的自动化关卡)——规范靠工具执行,不靠自觉。
2. 为什么重要
代码是给人读的(Python 尤甚);统一风格消除无谓评审争论,静态检查在运行前抓 30-50% 的低级错误。工具链 10 分钟配好,收益覆盖项目全生命周期。
3. 前置知识
kp-021(环境)、kp-035(测试)、kp-036(pyproject)。
4. 核心概念
toml
# pyproject.toml 统一配置
[tool.ruff]
line-length = 100
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM"] # 常见错误/导入排序/过时语法/陷阱/简化
ignore = ["E501"]
[tool.mypy]
python_version = "3.12"
check_untyped_defs = trueyaml
# .pre-commit-config.yaml:提交即检查
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.0
hooks:
- id: ruff # lint
- id: ruff-format # 格式化
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: end-of-file-fixer
- id: check-merge-conflict5. 原理与机制
PEP 8 的核心条款(工具会自动执行大半,人工只需记住原则):
text
命名:模块/函数 snake_case;类 PascalCase;常量 UPPER_CASE
导入:标准库 → 第三方 → 本地,三组空行分隔(ruff I 规则)
空格:4 空格缩进;比较两侧空格、关键字参数默认值不加空格
行宽:≤ 88/100/120(团队统一即可,ruff-format 自动折)
文档:公共函数写 docstring(一句话 + 参数/返回,Google 或 NumPy 风格)质量门禁链(CI 与本地同款):
text
pre-commit(格式+lint)→ mypy(类型)→ pytest(行为)→ build(可安装)6. 关键事实(模型/图示)
text
项目分层建议(中小型服务):
src/app/
├── models.py # 数据结构(dataclass/Pydantic)
├── services.py # 业务逻辑(纯函数优先)
├── adapters.py # IO 边界(DB/HTTP/文件)
└── cli.py / api.py# 入口薄壳
原则:入口薄、业务纯、IO 靠边——service 层不 import http/db 才好测7. 直观类比
ruff 是自动校对员(错别字、格式、病句秒改);mypy 是语法老师(主谓宾搭配——类型不匹配);pre-commit 是出门前的门禁——不过检查别想出小区(提交)。三者让"代码规范"从道德要求变成物理约束。
8. 实例与案例
bash
# 30 分钟给老项目上质量链
uv add --dev ruff mypy pre-commit
pre-commit install
ruff check --fix . && ruff format .
uvx mypy src
pytest9. 常见误区
- 工具一多就全关 —— 新项目默认从严、遗留项目渐进(把告警写进 pyproject 逐个消灭),比"全关"或"全开"都可维护。
- 手写格式化争论 ——
ruff format一键统一;评审里不再讨论空格。 - 类型检查从 --strict 起步 —— 劝退率高;从
check_untyped_defs渐进收紧。 - linter 告警"以后再说" —— 告警即债务利息;要么修,要么显式
# noqa: 规则带理由。
10. 自测题
- ruff 取代了哪些老工具?为什么它够快?
- pre-commit 的执行时机与 CI 门禁的关系?
- "入口薄、业务纯、IO 靠边"对测试的意义?
参考答案
- flake8/pycodestyle/isort/black(格式与 lint 合一);Rust 实现 + 缓存 + 并行,比 Python 实现快 10-100 倍。
- 本地提交时拦截(git pre-commit hook);CI 里重跑同款规则做第二道门禁——本地快反馈,CI 保兜底。
- service 层不依赖 IO 即可脱离网络/数据库直接单元测试;mock 只需要留在 adapters 边界。
11. 与其他知识点的关系
12. 延伸阅读
- PEP 8 原文:https://peps.python.org/pep-0008/
- ruff 配置手册:https://docs.astral.sh/ruff/