不用各种概念,说点实在的。
我从去年开始带一个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"能找到。
有问题评论区问,看到了回。


