欢迎光临
我们一直在努力

代码质量不是靠嘴说的——我靠这套工具链把Review时间砍了一半

不用各种概念,说点实在的。

我从去年开始带一个5人的小团队。项目越堆越多,代码越来越乱。每次Code Review,光格式问题就占了一半评论——缩进不对、命名不规范、空行多一行少一行。Reviewer看着烦,提交者也委屈。

后来搞了套工具链,把能自动检查的事全扔给机器,人在Review里只聊业务逻辑。

效果很直接:Review从每人半小时缩到10分钟。不是吹的,有CI记录可以翻。

## flake8 + pylint——常规检查不废话

这俩是老搭档了。flake8管格式和PEP8,pylint查更深层的问题——未使用的参数、过于复杂的函数、不该暴露的变量。

我一般在项目根目录放一个`.pylintrc`,核心配置长这样:

```ini

[MASTER]

fail-under=8.0

[MESSAGES CONTROL]

# flake8已经管了的,pylint这边关掉

disable=C0301,W0612,W0511

[FORMAT]

max-line-length=100

[BASIC]

good-names=i,j,k,x,y,z,ex,Run,_

bad-names=foo,bar,baz,tmp,temp

```

第一次跑`pylint src/`,175个warning,满江红。当时心都凉了。

但不用慌。我的做法是先把分数调到能接受的阈值,每周开会花10分钟修一批,两个迭代下来就降到个位数了。

**如果你不想一次性背历史包袱:**

```bash

# 只看新增代码,不管遗留问题

pylint –fail-under=8.0 src/ –ignore-patterns=old_module

```

新项目从第一天开始跑,旧项目逐步治理,不要回头一次性改完——改完了一个回归测试通不过,你更想哭。

## black + isort——格式化的事交给机器

格式问题是Review里最没必要花时间的。你写代码的时候觉得"这样好看",他觉得"那样好看",争起来没完。

我的规矩:不争,black说了算。

```bash

pip install black isort

# 一行搞定

isort src/ && black src/

```

isort管import的顺序——先标准库、再三方库、再项目内部,三段之间空一行。black管剩下的一切:空格、换行、引号、括号换行。

实际效果就是每个PR的改动里,再也不会有"这里多了一个空格"这样的评论了。

说实话,black有些地方格式化的确实丑,比如这种:

```python

# black会写成

result = some_function(

    arg1, arg2, arg3, arg4, arg5

)

```

看着像右括号多了个朋友。但我忍了,因为我个人的审美偏好没有团队一致性重要。

## mypy——类型检查比你想的有用

Python动态类型是双刃剑。写起来快,但很多bug只有跑起来才知道。mypy在写的时候就把这些拦住了。

**常见的翻车现场:**

```python

# 没有mypy你发现不了这个bug

def get_user(id: int) -> dict | None:

    if id <= 0:

        return None

    return {"id": id, "name": "张三"}

# 调用方可能没判空

user = get_user(-1)

print(user["name"])  # 💥 TypeError: 'NoneType' object is not subscriptable

```

mypy在CI里跑一遍就能拦下这类问题。

**我建议的分阶段方案:**

```bash

# 第1个月:只查有类型标注的文件

mypy src/ –check-untyped-defs

# 第2个月:开启严格模式,禁止Optional遗漏

mypy src/ –strict-optional

# 第3个月:全面严格

mypy src/ –strict

```

别上来就`–strict`,团队会骂娘。先让大家尝到甜头,再慢慢收紧。

## pre-commit——在commit之前就把问题拦住

很多人靠CI拦住问题再回退,来回多一个commit。不如在`git commit`之前就让检查跑起来。

```yaml

# .pre-commit-config.yaml

repos:

  – repo: https://github.com/psf/black

    rev: 24.10.0

    hooks:

      – id: black

        args: [–line-length=100]

  – repo: https://github.com/pycqa/isort

    rev: 5.13.2

    hooks:

      – id: isort

        args: [–profile=black]

  – repo: https://github.com/pycqa/flake8

    rev: 7.1.1

    hooks:

      – id: flake8

        args: [–max-line-length=100]

```

安装也简单:

```bash

pip install pre-commit

pre-commit install

```

之后每次commit,自动先跑格式化再跑检查,通过了才让你提交。没通过的话代码已经被black自动改好了,你`git add`改完的文件再commit就行。

**几个小坑:**

1. pre-commit要`.git`目录存在才能装hook,git clone下来的没问题,`git init`后记得跑一次`pre-commit install`

2. 跑第一次很慢——它要去下载hook对应的版本。后面就快了,几秒完事

3. 如果CI里也跑同样的检查,建议两边的规则版本保持一致,不然可能会出现"本地过了,CI不过"的情况

## 整套东西长什么样

项目根目录的`quality.sh`:

```bash

#!/bin/bash

set -e

echo "=== isort ==="

isort src/ –check-only –diff

echo "=== black ==="

black src/ –check –diff

echo "=== flake8 ==="

flake8 src/ –max-line-length=100 –statistics

echo "=== mypy ==="

mypy src/ –check-untyped-defs

echo "=== pylint ==="

pylint src/ –fail-under=8.0

echo "=== 全部通过 ==="

```

CI脚本(GitHub Actions):

```yaml

# .github/workflows/quality.yml

name: Code Quality

on: [push, pull_request]

jobs:

  check:

    runs-on: ubuntu-latest

    steps:

      – uses: actions/checkout@v4

      – uses: actions/setup-python@v5

        with:

          python-version: "3.11"

      – run: pip install flake8 pylint black isort mypy

      – run: bash quality.sh

```

原则很简单:本地跑不过的,CI也别想过。一样的东西,跑两遍。

CI跑不过的PR不能合。这是我们唯一硬性规定,其他的都好商量。

## 几个坑

1. **pylint和flake8规则有重叠** — flake8禁的pylint也禁,同时报两遍。解决方案:flake8管代码风格,pylint管逻辑质量,重叠的从pylint里`–disable`掉,留下一家管。我的`.pylintrc`里专门有一段`disable=C0301`来关掉行长度检查——这个让flake8管就够了。

2. **black格式化不按你审美来** — 我第一次看到black把多行参数拆成一行的时候也不爽。但它的**一致性**比你的**个人偏好**重要。团队统一比"谁对"更重要。我花了一周适应,之后就再没想过调格式的事了。

3. **mypy开始会全红** — 尤其是旧项目,变量全没类型标注,一跑上千个error。别硬上`–strict`,先`–check-untyped-defs`过渡一个月。等大家习惯了在函数签名里写类型,再慢慢收紧。

4. **pre-commit第一次跑很慢** — 它要去下载远程仓库里对应版本的hook脚本,网络不好的时候能卡几分钟。可以加上`–verbose`看进度,别以为它卡死了。

5. **本地和CI版本不一致会出问题** — flake8的一个小版本升级可能引入新规则,导致本地通过CI挂。我的做法:`requirements-quality.txt`里锁死版本号,本地和CI都用同一个文件装依赖。版本一致,结果就一致。

6. **旧项目历史债太多** — 一个跑了三年的项目,第一次跑pylint给了个2.3分。改是不可能全改的。我加了`–ignore-patterns=legacy/`把历史模块放过了,只在新代码上严格执行。老代码有空就修,没空先留着。

## 用了半年的感受

之前一个中型PR提上来,光review格式就要2-3轮对话。现在PR评论里讨论的全是"这里逻辑不对"、"这个接口设计不合理"——全都是真正有意义的东西。

review速度也快了。以前一个人review要半小时,现在10分钟能搞定,因为90%的废话检查已经自动过了。

最意外的收获是新人上手快了。新来的同事写代码,格式不对commit直接被拦,推荐写法被linter提醒——他边写边学,两个迭代后写的代码基本零warning。比让人带高效多了。

这套东西GitHub上有个现成的模板仓库,.pylintrc、pre-commit配置、CI脚本都放好了,clone下来改改项目名就能用。

链接就不贴了,搜关键词"python-quality-starter"能找到。

有问题评论区问,看到了回。

赞(0)
未经允许不得转载:171主机测评 » 代码质量不是靠嘴说的——我靠这套工具链把Review时间砍了一半
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址