用工具把 Python 代码质量变成可测量的工程习惯

2026-06-30 27 预计阅读时间: 1 分钟
来源: realpython.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:7 分钟

Python 代码质量不只是“看起来优雅”。真正能长期工作的代码,需要同时做到功能正确、可读、有效率、可复用,并且能被工具持续检查。围绕 Python 代码质量的测验提醒我们:质量不是一次性重构出来的,而是在日常开发、评审和 CI 中反复测量出来的。

代码质量的四个硬指标

一段 Python 代码先要能正确完成任务,这是底线。但工程里的“好代码”通常还要经得起几类压力。

可读性决定别人能不能快速理解你的意图。清晰的变量名、小函数、明确的控制流,比炫技式的一行表达式更有维护价值。Python 社区强调可读性,不是审美偏好,而是为了降低交接、排障和修改成本。

效率不等于提前微优化。更常见的问题是选择了错误的数据结构,或者在循环里做了不必要的重复计算。比如需要频繁判断元素是否存在时,set 往往比 list 更适合。

可复用性来自边界清晰的函数、模块和接口。把输入、输出、副作用说清楚,代码才容易被测试,也更容易被别的功能调用。

工具负责测量,人负责判断

Python 生态里有不少工具可以帮助发现质量问题,但它们解决的是不同层面的事情。

ruffflake8 这类 linter 擅长发现未使用变量、复杂表达式、风格不一致等问题。black 负责统一格式,减少团队在代码排版上的争论。mypypyright 可以通过类型提示提前发现一部分调用错误。pytest 则验证行为是否符合预期。

这些工具不能替代设计判断。比如一个函数通过了格式化、lint 和类型检查,仍然可能职责过多、命名含糊、测试覆盖了错误的行为。工具的价值是把机械检查自动化,让评审者把注意力放在抽象、边界和业务语义上。

可以这样实践:给一个小项目加质量检查

下面是一个可以直接复制运行的最小示例。它演示了如何用测试、格式化、lint 和类型检查一起守住 Python 代码质量。

创建项目文件:

mkdir python-quality-demo
cd python-quality-demo
python -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install pytest ruff black mypy

创建 quality_demo.py

from __future__ import annotations


def unique_sorted_names(names: list[str]) -> list[str]:
    """Return normalized, unique names in alphabetical order."""
    cleaned = {name.strip().title() for name in names if name.strip()}
    return sorted(cleaned)


def average_score(scores: list[float]) -> float:
    if not scores:
        raise ValueError("scores must not be empty")
    return sum(scores) / len(scores)

创建 test_quality_demo.py

import pytest

from quality_demo import average_score, unique_sorted_names


def test_unique_sorted_names_normalizes_and_deduplicates() -> None:
    assert unique_sorted_names([" alice ", "Bob", "ALICE", ""]) == ["Alice", "Bob"]


def test_average_score() -> None:
    assert average_score([80.0, 90.0, 100.0]) == 90.0


def test_average_score_rejects_empty_input() -> None:
    with pytest.raises(ValueError):
        average_score([])

运行检查:

black .
ruff check .
mypy .
pytest -q

如果你想把规则固化下来,可以加入 pyproject.toml

[tool.black]
line-length = 88

'tool.ruff'
line-length = 88

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"]

[tool.mypy]
python_version = "3.11"
strict = true

注意:上面的 TOML 片段里,[tool.ruff] 才是有效表头;如果复制时看到引号,请改成下面这个可用版本:

[tool.black]
line-length = 88

[tool.ruff]
line-length = 88

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B"]

[tool.mypy]
python_version = "3.11"
strict = true

把质量检查放进 CI,而不是靠记忆

本地检查很有用,但团队协作时,质量门槛最好由 CI 执行。可以这样实践一个 GitHub Actions 工作流:

name: Python quality

on:
  pull_request:
  push:
    branches: [main]

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install pytest ruff black mypy
      - name: Format check
        run: black --check .
      - name: Lint
        run: ruff check .
      - name: Type check
        run: mypy .
      - name: Test
        run: pytest -q

这类配置的关键不在于工具数量,而在于信号稳定。规则太松,发现不了问题;规则太激进,又会让团队绕开工具。成熟做法是从格式化、基础 lint、核心测试开始,再逐步提高类型检查和复杂度约束。

采用建议:别把质量做成仪式

Python 代码质量管理最怕变成“跑一堆命令,没人看结果”。更实用的做法是:

  • 新项目默认启用格式化、lint、测试和 CI。
  • 老项目先只检查改动文件,避免一次性清理拖垮交付。
  • 对公共函数、复杂业务规则、数据转换逻辑优先补测试。
  • 类型提示从模块边界开始加,比如 API 入参、返回值、核心模型。
  • 代码评审重点看命名、职责、异常处理和测试意图,而不是争论空格。

质量工具能测量很多东西,但不能替你定义“这段代码是否表达了正确的业务概念”。把机械问题交给工具,把设计问题留给工程师,Python 项目才会越改越稳,而不是越改越怕。


相关推荐