Python 代码质量不只是“看起来优雅”。真正能长期工作的代码,需要同时做到功能正确、可读、有效率、可复用,并且能被工具持续检查。围绕 Python 代码质量的测验提醒我们:质量不是一次性重构出来的,而是在日常开发、评审和 CI 中反复测量出来的。
代码质量的四个硬指标
一段 Python 代码先要能正确完成任务,这是底线。但工程里的“好代码”通常还要经得起几类压力。
可读性决定别人能不能快速理解你的意图。清晰的变量名、小函数、明确的控制流,比炫技式的一行表达式更有维护价值。Python 社区强调可读性,不是审美偏好,而是为了降低交接、排障和修改成本。
效率不等于提前微优化。更常见的问题是选择了错误的数据结构,或者在循环里做了不必要的重复计算。比如需要频繁判断元素是否存在时,set 往往比 list 更适合。
可复用性来自边界清晰的函数、模块和接口。把输入、输出、副作用说清楚,代码才容易被测试,也更容易被别的功能调用。
工具负责测量,人负责判断
Python 生态里有不少工具可以帮助发现质量问题,但它们解决的是不同层面的事情。
ruff、flake8 这类 linter 擅长发现未使用变量、复杂表达式、风格不一致等问题。black 负责统一格式,减少团队在代码排版上的争论。mypy 或 pyright 可以通过类型提示提前发现一部分调用错误。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 项目才会越改越稳,而不是越改越怕。