>>>PyPathPython 学习站
前沿与实践 · Frontier & Practice lv.4 前沿 kp-045

工程规范与代码质量

前置知识:kp-021、kp-035、kp-036

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 = true

yaml
# .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-conflict

5. 原理与机制

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
pytest

9. 常见误区

  1. 工具一多就全关 —— 新项目默认从严、遗留项目渐进(把告警写进 pyproject 逐个消灭),比"全关"或"全开"都可维护。
  2. 手写格式化争论 —— ruff format 一键统一;评审里不再讨论空格。
  3. 类型检查从 --strict 起步 —— 劝退率高;从 check_untyped_defs 渐进收紧。
  4. linter 告警"以后再说" —— 告警即债务利息;要么修,要么显式 # noqa: 规则 带理由。

10. 自测题

  1. ruff 取代了哪些老工具?为什么它够快?
  2. pre-commit 的执行时机与 CI 门禁的关系?
  3. "入口薄、业务纯、IO 靠边"对测试的意义?
参考答案
  1. flake8/pycodestyle/isort/black(格式与 lint 合一);Rust 实现 + 缓存 + 并行,比 Python 实现快 10-100 倍。
  2. 本地提交时拦截(git pre-commit hook);CI 里重跑同款规则做第二道门禁——本地快反馈,CI 保兜底。
  3. service 层不依赖 IO 即可脱离网络/数据库直接单元测试;mock 只需要留在 adapters 边界。

11. 与其他知识点的关系

  • kp-026 类型注解:mypy 的输入。
  • kp-035 测试:质量链的行为验证环节。
  • kp-037 日志:规范里常含日志格式约定。

12. 延伸阅读

  • PEP 8 原文:https://peps.python.org/pep-0008/
  • ruff 配置手册:https://docs.astral.sh/ruff/