小白学 Python
课程GitHub
© 2026 小白学 Python · 基于 walter201230/Python 教程
课程目录GitHub
Python 环境加载中…

ruff:一站式代码检查

本章为概念阅读 · 预计 18 分钟

教学 01 / 05· 已读

ruff:一个工具替掉 black + flake8 + isort + pyupgrade

这一章是纯阅读章节,没有练习题。

ruff 是命令行工具,浏览器里的 Pyodide 跑不起来。这一章我们把概念、用法、配置讲清楚,各位在自己本地装好 Python 环境之后实际跑一遍就能掌握。

各位还记不记得 2022 年那会儿,开一个 Python 新项目,光「保证代码风格统一」这件事就要装一堆东西:

  • black:自动格式化代码,管缩进、换行、引号
  • flake8:检查语法错误、未使用变量、命名不规范
  • isort:把 import 语句按字母顺序、按分组重新排列
  • pyupgrade:把老语法升级到新版本,比如 Dict[str, int] 改成 dict[str, int]
  • pydocstyle:检查 docstring 写得规不规范
  • bandit:扫一扫有没有安全漏洞

六个工具,六份配置文件,六套规则,每个工具自己装一遍,CI 上每个跑一遍,commit 之前每个调一遍。配一个新项目的 lint 流水线,光研究这些工具怎么互相不打架就能花掉半天。

直到 2022 年底,Astral 公司——就是上一章那个写 uv 的 Astral——丢出来一个叫 ruff 的东西。这家公司有个特点:用 Rust 重写 Python 工具链,并且比原版快 10 到 100 倍。

ruff 一上来就把 flake8、isort、pyupgrade、pydocstyle、bandit 这些工具的规则一口气全实现了,后来又补上了 format 子命令,把 black 的功能也吃掉了。一个二进制文件,一份配置,一套命令。

到 2024 年,ruff 已经是 Python 社区的事实标准,Pandas、FastAPI、Pydantic、Hugging Face Transformers、Apache Airflow 都换了过去。到 2026 年的今天,各位开新项目,几乎不会再有人推荐用 flake8 + black + isort 这套老组合了。

这一章学完之后,各位应该能:

  1. 在新项目里五分钟内配好 ruff
  2. 看懂别人 pyproject.toml 里那一坨 [tool.ruff] 配置
  3. 把 ruff 接进 pre-commit、CI、编辑器
  4. 把老项目从 black + flake8 + isort 平滑迁移过来

老办法到底烦在哪

先回忆一下老办法是怎么个用法。一个比较「正经」的项目,根目录下通常会出现这些配置:

my-project/
├── pyproject.toml         # 部分工具的配置
├── setup.cfg              # flake8 必须放这里(或单独的 .flake8)
├── .flake8                # flake8 配置(可选)
├── .isort.cfg             # isort 配置(可选)
├── .pre-commit-config.yaml
└── ...

每个工具有自己偏好的配置文件位置:

  • black 看 pyproject.toml 的 [tool.black]
  • flake8 死活不支持 pyproject.toml,只能用 .flake8 或 setup.cfg
  • isort 可以放 pyproject.toml、.isort.cfg、setup.cfg,看心情
  • pyupgrade 没配置文件,全靠命令行参数

这就埋了第一个坑——配置散落各处,新人接手项目,光找配置文件就要找半天。

第二个坑是工具之间会打架。最经典的就是 black 和 flake8 冲突。black 默认行宽 88 字符,flake8 默认行宽 79 字符。两个不调一致,black 格式化完,flake8 就报 E501 line too long。

isort 和 black 也会打架。isort 默认按某种风格排 import,black 不一定接受,要给 isort 加上 --profile black 才能一致。

第三个坑是慢。一个中型项目,跑 flake8 . 几秒到几十秒;跑 black . 几秒到十几秒;跑 isort . 也要几秒。CI 上串起来跑一遍,几十秒就没了。本地保存文件时想跑一遍 lint,慢到没法接进编辑器。

教学 02 / 05· 已读

ruff 是个啥

ruff 是 Astral 公司开源的 Python 代码检查 + 格式化工具。两个关键属性:

  1. 用 Rust 写的。Python 工具用 Python 写,速度天花板就在那里。换成 Rust,速度能上一两个数量级
  2. 一个工具替掉一堆。flake8、black、isort、pyupgrade、pydocstyle、bandit、pylint 的部分规则、autoflake,全部内置

看一下 ruff 官方公布的速度对比。在 CPython 项目(约 25 万行代码)上跑:

工具耗时
flake812 秒左右
pylint几分钟
ruff check0.4 秒左右

这速度有什么用?两点重要:

  1. 保存文件时实时跑 lint 成为可能。编辑器里每次 Ctrl+S,ruff 后台跑一遍,几乎感觉不到延迟
  2. CI 时间短。从前 lint 阶段要 30 秒,现在 1 秒就过了

「那它支持多少规则?」截至 2026 年,ruff 已经实现了 800 多条规则,覆盖了 flake8 主线 + 几十个 flake8-* 插件 + isort + pyupgrade + pydocstyle + pylint 的一部分 + bandit 的一部分。换句话说,几乎所有主流 Python lint 工具的能力,ruff 都吃下来了。

常用规则集一览

ruff 用「字母前缀」给规则分组:

前缀来源工具管什么
EpycodestylePEP 8 风格错误(缩进、空格)
WpycodestylePEP 8 风格警告
Fpyflakes未使用变量、未定义引用、import 错
Iisortimport 排序与分组
UPpyupgrade老语法升级到新版本
Bflake8-bugbear常见 bug 模式
SIMflake8-simplify代码简化建议
Npep8-naming命名规范(驼峰、下划线)
Dpydocstyledocstring 规范
Sflake8-bandit安全漏洞检查
ANNflake8-annotations类型注解检查
C4flake8-comprehensions推导式优化
RETflake8-returnreturn 语句风格
ARGflake8-unused-arguments未使用参数
PTflake8-pytest-stylepytest 风格
PLpylintpylint 部分规则
RUFruffruff 自家原创规则

完整清单官方文档里有,叫「Rules」页面,规则号、说明、是否能自动修都列得清清楚楚。

ruff vs black + flake8 + isort 对照表

维度老组合ruff
工具数量至少 3 个(black + flake8 + isort),加 pyupgrade、pydocstyle 更多1 个
配置位置散落在 pyproject.toml、.flake8、setup.cfg 等全部在 pyproject.toml
速度几秒到几十秒通常 1 秒以内
规则数量各家加起来约 500 条800+ 条
自动修复部分支持(black、isort、pyupgrade 自动;flake8 不修)大部分规则支持
实现语言PythonRust
二进制依赖安装 Python 包单二进制(也能 pip 装)
编辑器实时 lint慢,体验差快,体验丝滑
pyproject.toml 支持部分(flake8 不支持)完全支持

一个常见坑:和 mypy 的关系

很多童鞋会问:「ruff 能替代 mypy 吗?」

不能。

ruff 是 lint + formatter,做的是「代码风格、常见错误模式」检查。mypy 是类型检查器,做的是「这个变量传给那个函数,类型对不对」这种全局类型推导。两者是不同维度的工具,互补使用。

正确的姿势:

  • 用 ruff 管风格、import、明显 bug、语法升级
  • 用 mypy 或者 pyright 管类型

CI 上两个都跑:

- run: ruff check .
- run: ruff format --check .
- run: mypy .

ruff 倒是有几条规则(前缀 ANN)会做粗浅的类型注解检查,比如「这个函数没有写 return 类型」。但是它不会真正去推导类型一致性,复杂的类型问题还是要靠 mypy。

教学 03 / 05· 已读

安装与第一次跑

老规矩,推荐用 uv 装:

uv add --dev ruff

--dev 的意思是「装到开发依赖组」,发布生产环境时不会带上。ruff 是开发工具,只在开发和 CI 时用,所以放 --dev 最合适。

如果项目还没用 uv,用 pip 装也行:

pip install ruff

或者用 pipx 装成全局命令:

pipx install ruff

装完之后,验证一下:

ruff --version

输出类似:

ruff 0.8.0

第一次跑

进项目目录,跑一下:

ruff check .

这条命令会扫描当前目录下所有 .py 文件,按默认规则检查。各位第一次跑大概率会看到一堆告警:

foo.py:3:1: F401 [*] `os` imported but unused
foo.py:8:5: E731 Do not assign a `lambda` expression, use a `def`
bar.py:12:80: E501 Line too long (95 > 79)

格式很清晰:文件名:行:列: 规则号 描述。规则号前面如果带个 [*],说明这条规则可以自动修复。

要让 ruff 自动修,加 --fix:

ruff check --fix .

跑完之后,os imported but unused 这种问题,ruff 直接把那行 import os 删掉了。

格式化代码用另一个子命令:

ruff format .

这条命令的行为基本和 black . 一样——把整个项目的代码风格统一到一致的缩进、引号、换行规则。

把这两条命令加在一起,就是日常 commit 之前的标准流程:

ruff check --fix . && ruff format .

先 lint 再 format,齐活。

自动修复实战

ruff check --fix . 能修哪些东西?挑几个常见的看看。

F401:未使用的 import

python
import os
import sys

print(sys.version)

ruff check --fix 之后:

python
import sys

print(sys.version)

os 没用上,直接删掉。

E711:和 None 比较应该用 is

python
if x == None:
    print("x 是 None")

修复后:

python
if x is None:
    print("x 是 None")

为什么要改?因为 == 会触发 __eq__ 方法,有些类的 __eq__ 实现得稀奇古怪(比如 numpy 数组),跟 None 比较会出意想不到的结果。is None 是身份比较,永远只看「是不是同一个对象」,绝对安全。

C408:不必要的 list/dict/tuple 调用

python
empty = list()
d = dict()
t = tuple()

修复后:

python
empty = []
d = {}
t = ()

list() 和 [] 等价,但是 list() 要去全局名字空间里查 list 这个名字、再调用,慢一点。直接写字面量更快也更短。

UP006:用新版类型注解

python
from typing import List, Dict

def foo(x: List[int]) -> Dict[str, int]:
    pass

修复后(target-version = "py39" 以上):

python
def foo(x: list[int]) -> dict[str, int]:
    pass

Python 3.9+ 已经支持直接用 list[int] 写类型注解,不用再从 typing 里 import 了。

UP008:用 super() 不要带参数

python
class Foo(Bar):
    def __init__(self):
        super(Foo, self).__init__()

修复后:

python
class Foo(Bar):
    def __init__(self):
        super().__init__()

Python 3 里 super() 不传参数就够了,老 Python 2 风格的 super(Foo, self) 是历史包袱。

I001:import 排序

python
import sys
from my_project import utils
import os
import requests

修复后:

python
import os
import sys

import requests

from my_project import utils

ruff 把 import 按「标准库 → 第三方 → 第一方」分成三组,每组之间空一行,组内按字母序排。这等同于跑了一遍 isort。

不安全修复

有些修复 ruff 不会默认做,因为可能改变行为。比如把 dict() 改成 {}——99% 情况下等价,但是如果你的代码里 dict 这个名字被覆盖了,行为就变了。这种修复叫「unsafe fix」,要加 --unsafe-fixes 才会做:

ruff check --fix --unsafe-fixes .

各位如果心里没底,先 ruff check --fix . 跑安全的,再用 --unsafe-fixes 单独跑一遍并 review 改动。

ruff format:black 替代品

ruff format . 干的事跟 black . 几乎一样:

  • 行宽默认 88
  • 字符串默认双引号
  • 缩进 4 空格
  • 函数参数过长自动换行
  • 字典、列表、set 字面量按一致风格排版

格式化前:

python
def foo(a,b,c, d ):
    return  {  'name':a,'age':b,'list':[1,2,3]  }

ruff format . 之后:

python
def foo(a, b, c, d):
    return {"name": a, "age": b, "list": [1, 2, 3]}

Astral 在文档里明确写过「ruff format 与 black 99.9% 兼容」,各位从 black 迁过来不用担心代码风格突变。

ruff format 也支持 --check 模式,只检查不改:

ruff format --check .

如果有文件需要格式化,命令返回非零 exit code,CI 上可以拿来卡住「忘了 format 就提交」的 PR。

教学 05 / 05

配置:pyproject.toml

ruff 的配置全部塞进 pyproject.toml,没有别的文件。配置长这样:

[tool.ruff]
# 行宽,跟 black 默认一致
line-length = 88

# 目标 Python 版本,影响某些规则的判断
target-version = "py312"

# 排除哪些目录
exclude = [
    ".git",
    ".venv",
    "build",
    "dist",
    "__pycache__",
    "migrations",
]

[tool.ruff.lint]
# 启用哪些规则集
select = ["E", "F", "I", "UP", "B", "SIM"]

# 忽略哪些具体规则
ignore = ["E501"]

[tool.ruff.format]
# 引号风格:双引号优先(black 风格)
quote-style = "double"
# 缩进风格:空格
indent-style = "space"

line-length

行宽。默认 88,跟 black 一致。喜欢 100 也行:

line-length = 100

target-version

目标 Python 版本。这个值影响一些规则的判断。比如 target-version = "py312",ruff 知道 dict[str, int] 这种语法你能用,会建议把老代码里的 Dict[str, int] 改过来。

合法值:py38、py39、py310、py311、py312、py313、py314。

exclude

不扫描哪些目录。.git、.venv、build、dist 这些 ruff 默认就会排除,但是 migrations(Django 项目自动生成的迁移文件)这种,需要自己加。

select

最重要的字段——启用哪些规则集。

新项目第一次配,推荐这一套:

select = ["E", "F", "I", "UP", "B", "SIM"]

E + F 是基本款(PEP 8 + pyflakes),I 管 import 排序,UP 把老语法升级到新版本,B 抓常见 bug,SIM 给一些简化建议。这六组覆盖了 80% 的需求,又不会噪声太大。

如果项目对代码质量要求高,再加上 N(命名规范)、C4(推导式)、RET(return)、ARG(未用参数)。

如果还要加 docstring 检查(D),各位要做好心理准备——pydocstyle 的规则很严格,老项目一开就是几百条告警。建议从 select = ["D"] + ignore = ["D100", "D101", "D102", ...] 一条条试,别一上来就全开。

ignore

忽略某些具体规则。比如 E501(行太长),有些项目觉得 88 字符不够用,就加进 ignore:

ignore = ["E501"]

或者忽略整个组:

ignore = ["D"]

per-file-ignores

按文件忽略规则。__init__.py 经常有未使用的 import(其实是用来重导出的),不想被告警,可以这样:

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
"tests/*" = ["S101", "ANN"]

tests/* 里允许用 assert(S101),不要求每个测试函数都写类型注解(ANN)。

isort 子配置

I 规则集(isort 替代)有自己的子配置,放 [tool.ruff.lint.isort]:

[tool.ruff.lint.isort]
# 把这些当成「第一方」包,跟其他第三方分开排
known-first-party = ["my_project"]

# import 块的分组顺序
section-order = [
    "future",
    "standard-library",
    "third-party",
    "first-party",
    "local-folder",
]

known-first-party 这个配置很常用——告诉 ruff「my_project 是我自己的包」,ruff 就会把它的 import 放到独立的一组,不跟第三方包混在一起。

完整配置示例

放一份生产可用的 pyproject.toml 配置,各位可以直接抄回去改:

[tool.ruff]
line-length = 88
target-version = "py312"
exclude = [
    ".git",
    ".venv",
    "build",
    "dist",
    "__pycache__",
    "migrations",
    "*.ipynb",
]

[tool.ruff.lint]
select = [
    "E",   # pycodestyle errors
    "W",   # pycodestyle warnings
    "F",   # pyflakes
    "I",   # isort
    "UP",  # pyupgrade
    "B",   # flake8-bugbear
    "SIM", # flake8-simplify
    "C4",  # flake8-comprehensions
    "N",   # pep8-naming
    "RET", # flake8-return
]
ignore = [
    "E501",  # 行太长,交给 formatter 处理
    "B008",  # 函数默认参数里调用函数,FastAPI 的 Depends 用法
]

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
"tests/*" = ["S101"]

[tool.ruff.lint.isort]
known-first-party = ["my_project"]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "auto"

抄这份过去,改一下 target-version 和 known-first-party,基本就能用。

noqa 注释:让 ruff 闭嘴

有些时候你确实想让 ruff 闭嘴。比如某行代码里 eval() 用得有充分理由,但 S307 会告警。这时候可以加 # noqa 注释:

python
result = eval(user_input)  # noqa: S307

# noqa: S307 表示「这行代码忽略 S307 这条规则」。多条规则用逗号隔开:

python
result = eval(user_input)  # noqa: S307, S102

裸的 # noqa(不指定规则号)也行,但是不推荐——会把这行所有规则都忽略,相当于关大灯。指定规则号最精准。

各位写 # noqa 之前最好先想想:是这个规则不合理,还是代码本身就该改?大多数时候是后者。

ruff 自家规则:RUF 系列

ruff 除了搬运别家规则,也自己原创了一些规则,前缀是 RUF。

RUF001:模糊字符

代码里出现「看着是英文字母但其实是希腊字母、全角字符」这种字符,会触发 RUF001。比如:

python
result = data["nаme"]  # 这里的 а 是西里尔字母 а,不是英文 a

肉眼几乎看不出来,但是程序跑起来会找不到键报 KeyError。ruff 能识别出这种字符并告警。

RUF005:用解包代替 list 拼接

python
new_list = [1, 2, 3] + list(other)

ruff 建议改成:

python
new_list = [1, 2, 3, *other]

解包语法更快、更短,还能直接拼任何可迭代对象。

RUF013:隐式 Optional 类型

python
def greet(name: str = None):
    print(f"Hello, {name}")

这个写法很常见,但其实有问题——name 默认是 None,但类型注解写的是 str,前后不一致。ruff 会建议改成:

python
def greet(name: str | None = None):
    print(f"Hello, {name}")

RUF100:未使用的 noqa

python
x = 1  # noqa: F401

如果这一行其实没有任何 lint 告警,那个 # noqa 就是垃圾。ruff 会专门把这种「过期 noqa」标出来,提醒各位删掉。

教学 04 / 05

集成:pre-commit、CI、编辑器

集成 pre-commit

pre-commit 是一个 git hook 框架,让各位在 git commit 时自动跑一些检查。装一下:

uv add --dev pre-commit
pre-commit install

然后在项目根目录建 .pre-commit-config.yaml:

repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.8.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

这一段配置干了两件事:

  1. ruff hook:跑 ruff check --fix,自动修能修的
  2. ruff-format hook:跑 ruff format

每次 git commit,pre-commit 会自动跑这两个 hook,跑通才让 commit。

rev: v0.8.0 怎么填?pre-commit 上有命令自动填最新版:

pre-commit autoupdate

跑一下,.pre-commit-config.yaml 里的版本号就更新到最新了。建议各位每隔几个月跑一次。

第一次装好 pre-commit,可以手动跑一遍:

pre-commit run --all-files

把项目里所有文件都过一遍,把历史欠债一次性清干净。

集成 GitHub Actions CI

ruff 在 CI 上的用法非常简单。新建 .github/workflows/lint.yml:

name: Lint

on:
  push:
    branches: [main]
  pull_request:

jobs:
  ruff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v3

      - name: Install ruff
        run: uv tool install ruff

      - name: Run ruff check
        run: ruff check --output-format=github .

      - name: Run ruff format check
        run: ruff format --check .

--output-format=github 这个选项很重要——它把告警输出成 GitHub Actions 能识别的格式,PR 页面上会直接在出问题的代码行上显示一个小标记,鼠标悬停就能看到具体规则和说明。

也有官方做的 action,更省事:

- name: Run ruff
  uses: astral-sh/ruff-action@v3

这个 action 自动装 ruff 并跑 ruff check,一行搞定。

CI 时间方面,ruff 这部分通常 5 秒以内跑完(包括环境准备),比从前 flake8 + black + isort 那一套快太多。

集成编辑器

代码风格工具最后一公里——编辑器集成。装好之后,每次保存文件,编辑器自动跑 ruff,问题立刻显示在出错的行上。

VS Code

装这个插件:Ruff(charliermarsh.ruff)。

装完之后,settings.json 里加几行:

{
    "[python]": {
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
            "source.fixAll.ruff": "explicit",
            "source.organizeImports.ruff": "explicit"
        }
    }
}

效果:

  • 保存文件时自动跑 ruff format
  • 自动应用所有能自动修的 lint 修复
  • 自动整理 import

PyCharm

PyCharm 有官方支持的 Ruff 插件,去 Settings → Plugins 搜「Ruff」装上。

装完之后:

  • Settings → Tools → Ruff:勾上「Use ruff format」、「Run ruff on save」
  • Settings → Editor → Code Style → Python:行宽改成 88,跟 ruff 一致

PyCharm 的好处是检查在编辑时实时显示,不用等保存。

Neovim / Vim

通过 nvim-lspconfig + mason.nvim 装 ruff 的 LSP server:

require("lspconfig").ruff.setup({})

或者直接用 null-ls / none-ls 的 ruff 集成。

从 black + flake8 + isort 迁移

老项目要换过来,怎么办?步骤:

第一步:装 ruff

uv add --dev ruff

第二步:写 ruff 配置

参考前面的「完整配置示例」,写一份 [tool.ruff] 进 pyproject.toml。line-length、target-version 等关键参数对齐原来 black 的配置。

第三步:跑一遍看看差异

ruff check .
ruff format --check .

ruff format 跟 black 99.9% 兼容,但还是会有少量文件被改。各位先 ruff format . 跑一遍,git diff 看一下,确认改动可接受再提交。

第四步:删掉老工具

uv remove --dev black flake8 isort pyupgrade

第五步:删配置

.flake8 删掉,setup.cfg 里的 [flake8] 段删掉,pyproject.toml 里的 [tool.black]、[tool.isort] 段删掉。

第六步:更新 pre-commit 和 CI

.pre-commit-config.yaml 里把 black、flake8、isort 的 hook 删掉,换成 ruff 的。CI 同理。

几个易踩的坑

坑 1:select 写错前缀

select = ["E1"] 不会启用 pycodestyle E1xx 这一组,只会启用 E1 这一条。要启用 E1xx 整组,要写 select = ["E1"] 或者更宽的 select = ["E"]。

具体规则:

  • "E":启用所有 E 开头的规则
  • "E1":启用所有 E1xx 开头的规则
  • "E101":只启用 E101 这一条

坑 2:select 和 ignore 同时写

select = ["E"]
ignore = ["E501"]

这样配的意思是「启用 E 全组,但 E501 这条不要」。这是合法的,ignore 优先级高。这是标准用法。

坑 3:ruff format 不读 [tool.ruff.lint] 的配置

[tool.ruff.lint] 管 lint,[tool.ruff.format] 管 format,两者完全独立。最常见的踩坑是:在 [tool.ruff.lint] 里设了 quote-style = "double",结果 ruff format 还是按默认风格跑。

# 错误位置
[tool.ruff.lint]
quote-style = "double"  # 这里写了没用

# 正确位置
[tool.ruff.format]
quote-style = "double"

坑 4:preview 规则

ruff 还有一批正在开发的「preview」规则,默认不启用。要打开:

[tool.ruff.lint]
preview = true

或者命令行 ruff check --preview。preview 规则的好处是抢先用上新东西,坏处是规则号、行为可能在版本之间变。生产项目稳着来,不建议默认开 preview。

坑 5:忘了升级 pre-commit hook 版本

各位 .pre-commit-config.yaml 里的 rev: v0.8.0 是写死的,ruff 升了新版本不会自动同步。建议每个月或每个季度跑一次 pre-commit autoupdate。

小结

各位走完这一章,应该已经能:

  1. 装 ruff:uv add --dev ruff
  2. 跑 ruff:ruff check --fix . 和 ruff format .
  3. 配 ruff:pyproject.toml 里写 [tool.ruff.lint] select = ["E", "F", "I", "UP", "B", "SIM"]
  4. 接 pre-commit:写 .pre-commit-config.yaml,加 ruff-pre-commit 仓库
  5. 接 CI:GitHub Actions 用 astral-sh/ruff-action@v3
  6. 接编辑器:VS Code 装 charliermarsh.ruff 插件,配置保存时自动 format

这套工作流配好之后,新项目从零到「能自动检查、能自动修复、能 CI 兜底、能编辑器实时反馈」只需要十分钟。代码风格的事,交给 ruff 就行。

本章目录

ruff:一站式代码检查

  1. 教学 01ruff:一个工具替掉 black + flake8 + isort + pyupgrade
  2. 教学 02ruff 是个啥
  3. 教学 03安装与第一次跑
  4. 教学 05配置:pyproject.toml
  5. 教学 04集成:pre-commit、CI、编辑器
← 上一章23 · pyproject.toml + uv
ruff:一站式代码检查
下一章 →25 · pytest:测试框架