Ruff 完全指南:下一代 Python Linter 与 Formatter

核心目标:全面掌握 Ruff 的安装配置、规则体系、自动修复、IDE 集成和生产级 CI/CD 工作流,实现 Python 代码质量检查从"跑完喝杯咖啡"到"瞬间完成"的升级。

前置知识:Python 3.8+ 基础、了解 pip / pyproject.toml,了解 Flake8 / Black / isort 等传统工具更佳。


1.1 什么是 Ruff

Ruff 是一个用 Rust 编写 的极速 Python linter 和 formatter,由 Astral 团队开发。它在单个工具中整合了 Flake8、isort、pyupgrade、pylint、pydocstyle 等数十个工具的功能。
#mermaid-svg-KG2K9qeZjZMHZvMQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KG2K9qeZjZMHZvMQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KG2K9qeZjZMHZvMQ .error-icon{fill:#552222;}#mermaid-svg-KG2K9qeZjZMHZvMQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KG2K9qeZjZMHZvMQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KG2K9qeZjZMHZvMQ .marker.cross{stroke:#333333;}#mermaid-svg-KG2K9qeZjZMHZvMQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KG2K9qeZjZMHZvMQ p{margin:0;}#mermaid-svg-KG2K9qeZjZMHZvMQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KG2K9qeZjZMHZvMQ .cluster-label text{fill:#333;}#mermaid-svg-KG2K9qeZjZMHZvMQ .cluster-label span{color:#333;}#mermaid-svg-KG2K9qeZjZMHZvMQ .cluster-label span p{background-color:transparent;}#mermaid-svg-KG2K9qeZjZMHZvMQ .label text,#mermaid-svg-KG2K9qeZjZMHZvMQ span{fill:#333;color:#333;}#mermaid-svg-KG2K9qeZjZMHZvMQ .node rect,#mermaid-svg-KG2K9qeZjZMHZvMQ .node circle,#mermaid-svg-KG2K9qeZjZMHZvMQ .node ellipse,#mermaid-svg-KG2K9qeZjZMHZvMQ .node polygon,#mermaid-svg-KG2K9qeZjZMHZvMQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KG2K9qeZjZMHZvMQ .rough-node .label text,#mermaid-svg-KG2K9qeZjZMHZvMQ .node .label text,#mermaid-svg-KG2K9qeZjZMHZvMQ .image-shape .label,#mermaid-svg-KG2K9qeZjZMHZvMQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-KG2K9qeZjZMHZvMQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KG2K9qeZjZMHZvMQ .rough-node .label,#mermaid-svg-KG2K9qeZjZMHZvMQ .node .label,#mermaid-svg-KG2K9qeZjZMHZvMQ .image-shape .label,#mermaid-svg-KG2K9qeZjZMHZvMQ .icon-shape .label{text-align:center;}#mermaid-svg-KG2K9qeZjZMHZvMQ .node.clickable{cursor:pointer;}#mermaid-svg-KG2K9qeZjZMHZvMQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KG2K9qeZjZMHZvMQ .arrowheadPath{fill:#333333;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KG2K9qeZjZMHZvMQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KG2K9qeZjZMHZvMQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KG2K9qeZjZMHZvMQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KG2K9qeZjZMHZvMQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KG2K9qeZjZMHZvMQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KG2K9qeZjZMHZvMQ .cluster text{fill:#333;}#mermaid-svg-KG2K9qeZjZMHZvMQ .cluster span{color:#333;}#mermaid-svg-KG2K9qeZjZMHZvMQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KG2K9qeZjZMHZvMQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KG2K9qeZjZMHZvMQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-KG2K9qeZjZMHZvMQ .icon-shape,#mermaid-svg-KG2K9qeZjZMHZvMQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KG2K9qeZjZMHZvMQ .icon-shape p,#mermaid-svg-KG2K9qeZjZMHZvMQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KG2K9qeZjZMHZvMQ .icon-shape .label rect,#mermaid-svg-KG2K9qeZjZMHZvMQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KG2K9qeZjZMHZvMQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KG2K9qeZjZMHZvMQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KG2K9qeZjZMHZvMQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 整合
🦀 Ruff (一个工具搞定)
Linter

700+ 规则
Formatter

Black 兼容
Import 排序

isort 兼容
Auto-fix

安全自动修复
传统工具链 (多个独立工具)
Flake8

pyflakes + pycodestyle
isort

import 排序
Black

代码格式化
pyupgrade

语法现代化
pylint

深度检查
pydocstyle

文档检查

1.1.1 速度对比------为什么用 Ruff

工具 Lint 10 万行 Lint 100 万行 底层语言
Ruff 0.05s 0.3s Rust
Flake8 3s 35s Python
Pylint 12s 140s Python
Black 2.5s 28s Python
bash 复制代码
# 同一个项目的实际测试:
# cpython 源码 (~200 万行 Python)
$ time ruff check .        # 0.3s real
$ time flake8 .             # 53s  real  ← Ruff 快 170 倍!
$ time pylint *.py          # 3min+      ← Ruff 快 600 倍!

Ruff 快到什么程度?你保存文件后还没松开手,lint 结果已经出来了。


1.2 安装与第一个命令

1.2.1 安装方式

bash 复制代码
# 推荐: pip 安装
pip install ruff

# 或使用 pipx (全局隔离)
pipx install ruff

# 验证安装
ruff --version
# ruff 0.6.x

1.2.2 第一个 lint 命令

python 复制代码
# bad_code.py ------ 一个有问题的文件
import os, sys, json            # ❌ 多模块一行
import collections              # ❌ 未使用的 import

unused_var = "hello"            # ❌ 未使用的变量

def my_function( x,y ):        # ❌ 括号内多余空格
    result=x+y                  # ❌ 操作符两边缺空格
    return result

print(my_function(1,2))        # ❌ 逗号后缺空格
bash 复制代码
# 直接运行 ruff check
ruff check bad_code.py

Ruff 输出

复制代码
bad_code.py:1:1: F401 [*] `collections` imported but unused
bad_code.py:1:10: F401 [*] `os` imported but unused
bad_code.py:1:14: F401 [*] `sys` imported but unused
bad_code.py:1:19: F401 [*] `json` imported but unused
bad_code.py:3:1: F841 [*] Local variable `unused_var` is assigned to but never used
bad_code.py:5:17: E201 Whitespace after '('
bad_code.py:5:19: E231 Missing whitespace after ','
bad_code.py:5:21: E202 Whitespace before ')'
bad_code.py:6:10: E225 Missing whitespace around operator
Found 9 errors.
[*] 9 fixable with the `--fix` option.

1.2.3 自动修复

bash 复制代码
# 一键修复所有可自动修复的问题
ruff check --fix bad_code.py

# 修复后的代码:
import collections              # 只移除了未使用的
# os, sys, json 已被删除

def my_function(x, y):          # ✅ 空格正确
    result = x + y              # ✅ 操作符空格正确
    return result

print(my_function(1, 2))        # ✅ 逗号后空格正确
# unused_var 被删除

2.1 Linter------700+ 规则体系

2.1.1 规则分类

Ruff 的规则按前缀分类,每个前缀对应一个工具或检查领域:
#mermaid-svg-a2ksZcFBGbfDHQe4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-a2ksZcFBGbfDHQe4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-a2ksZcFBGbfDHQe4 .error-icon{fill:#552222;}#mermaid-svg-a2ksZcFBGbfDHQe4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-a2ksZcFBGbfDHQe4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-a2ksZcFBGbfDHQe4 .marker.cross{stroke:#333333;}#mermaid-svg-a2ksZcFBGbfDHQe4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-a2ksZcFBGbfDHQe4 p{margin:0;}#mermaid-svg-a2ksZcFBGbfDHQe4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-a2ksZcFBGbfDHQe4 .cluster-label text{fill:#333;}#mermaid-svg-a2ksZcFBGbfDHQe4 .cluster-label span{color:#333;}#mermaid-svg-a2ksZcFBGbfDHQe4 .cluster-label span p{background-color:transparent;}#mermaid-svg-a2ksZcFBGbfDHQe4 .label text,#mermaid-svg-a2ksZcFBGbfDHQe4 span{fill:#333;color:#333;}#mermaid-svg-a2ksZcFBGbfDHQe4 .node rect,#mermaid-svg-a2ksZcFBGbfDHQe4 .node circle,#mermaid-svg-a2ksZcFBGbfDHQe4 .node ellipse,#mermaid-svg-a2ksZcFBGbfDHQe4 .node polygon,#mermaid-svg-a2ksZcFBGbfDHQe4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-a2ksZcFBGbfDHQe4 .rough-node .label text,#mermaid-svg-a2ksZcFBGbfDHQe4 .node .label text,#mermaid-svg-a2ksZcFBGbfDHQe4 .image-shape .label,#mermaid-svg-a2ksZcFBGbfDHQe4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-a2ksZcFBGbfDHQe4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-a2ksZcFBGbfDHQe4 .rough-node .label,#mermaid-svg-a2ksZcFBGbfDHQe4 .node .label,#mermaid-svg-a2ksZcFBGbfDHQe4 .image-shape .label,#mermaid-svg-a2ksZcFBGbfDHQe4 .icon-shape .label{text-align:center;}#mermaid-svg-a2ksZcFBGbfDHQe4 .node.clickable{cursor:pointer;}#mermaid-svg-a2ksZcFBGbfDHQe4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-a2ksZcFBGbfDHQe4 .arrowheadPath{fill:#333333;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-a2ksZcFBGbfDHQe4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a2ksZcFBGbfDHQe4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-a2ksZcFBGbfDHQe4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a2ksZcFBGbfDHQe4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-a2ksZcFBGbfDHQe4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-a2ksZcFBGbfDHQe4 .cluster text{fill:#333;}#mermaid-svg-a2ksZcFBGbfDHQe4 .cluster span{color:#333;}#mermaid-svg-a2ksZcFBGbfDHQe4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-a2ksZcFBGbfDHQe4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-a2ksZcFBGbfDHQe4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-a2ksZcFBGbfDHQe4 .icon-shape,#mermaid-svg-a2ksZcFBGbfDHQe4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a2ksZcFBGbfDHQe4 .icon-shape p,#mermaid-svg-a2ksZcFBGbfDHQe4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-a2ksZcFBGbfDHQe4 .icon-shape .label rect,#mermaid-svg-a2ksZcFBGbfDHQe4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a2ksZcFBGbfDHQe4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-a2ksZcFBGbfDHQe4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-a2ksZcFBGbfDHQe4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Ruff 规则体系 (700+)
F: Pyflakes
未使用的 import
未使用的变量
重复定义
E/W: pycodestyle
行太长
行尾空格
I: isort
import 顺序错误
D: pydocstyle
缺少模块文档
首句命令式
UP: pyupgrade
用 list 替代 typing.List
用 dict\[\] 替代 typing.Dict\[\]
B: flake8-bugbear
可变默认参数
raise 链保留
更多...
简化 (flake8-simplify)
类型检查导入
Pylint 规则
Ruff 专有规则

2.1.2 常用规则速查表

规则 序号 级别 说明 可修复
F401 --- Error 未使用的 import
F841 --- Error 未使用的变量
E501 79 Error 行过长
E711 --- Error == None 应用 is None
I001 --- Error import 未排序
UP006 --- Error 使用旧式 typing.List
B006 --- Error 可变默认参数
B904 --- Error raise 未保留异常链
SIM108 --- Error 可用三元表达式简化
SIM201 --- Error not a in ba not in b
D100 --- Error 缺少模块级 docstring
TCH001 --- Error 类型检查专用 import 应移入 TYPE_CHECKING
RUF100 --- Warn # noqa 注释指向不存在的规则

2.1.3 查看所有可用规则

bash 复制代码
# 列出所有规则
ruff rule --all

# 按前缀过滤
ruff rule --all | grep "^F"     # Pyflakes 规则
ruff rule --all | grep "^UP"    # pyupgrade 规则

# 查看某条规则的详情
ruff rule F401
# 输出: 规则描述、示例、出处、自动修复能力

2.2 配置------pyproject.toml 一站搞定

2.2.1 完整配置模板

toml 复制代码
# pyproject.toml
[tool.ruff]

# ── 目标 Python 版本 ──
target-version = "py311"       # 3.11 语法特性

# ── 行宽 ──
line-length = 100              # 超长警告阈值

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

# ── Linting 规则选择 ──
[tool.ruff.lint]
select = [
    # Pyflakes (基础错误)
    "F",
    # pycodestyle (代码风格)
    "E", "W",
    # isort (import 排序)
    "I",
    # pyupgrade (语法现代化)
    "UP",
    # flake8-bugbear (常见 bug)
    "B",
    # flake8-simplify (简化建议)
    "SIM",
    # 类型检查 import
    "TCH",
    # Pylint 规则 (部分)
    "PL",
    # Ruff 专有规则
    "RUF",
]

ignore = [
    # 允许行尾空白 (比如 Markdown 的换行)
    "W291",
    # 不强制文档字符串
    "D100", "D104",
]

# 修正特定规则配置
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]          # __init__.py 允许未使用 import
"tests/**/*.py" = ["PLR2004"]     # 测试文件中允许魔数
"scripts/*.py" = ["T201"]         # 脚本中允许 print

[tool.ruff.lint.isort]
known-first-party = ["myproject"] # 第一方包前缀
force-single-line = true          # 强制单行导入

[tool.ruff.lint.pylint]
max-args = 6                      # 最大函数参数数

# ── Formatter 配置 ──
[tool.ruff.format]
quote-style = "double"            # 双引号 (Black 默认)
indent-style = "space"            # 空格缩进
skip-magic-trailing-comma = false # 保留尾随逗号魔法
docstring-code-format = true      # 格式化 docstring 中的代码示例

2.2.2 按场景选择规则集

toml 复制代码
# ── 场景 1: 最小规则 (宽松, 只抓硬伤) ──
[tool.ruff.lint]
select = ["F", "E", "B"]          # Pyflakes + pycodestyle + bugbear

# ── 场景 2: 推荐规则 (日常开发) ──
[tool.ruff.lint]
select = ["F", "E", "W", "I", "UP", "B", "SIM", "TCH", "RUF"]

# ── 场景 3: 严格规则 (开源项目/团队规范) ──
[tool.ruff.lint]
select = [
    "F", "E", "W", "I", "D",         # + pydocstyle
    "UP", "B", "SIM", "TCH", "PL",   # + Pylint 子集
    "C4", "RUF", "T20", "PT"         # + 其他
]

2.2.3 配置优先级

#mermaid-svg-tylODKyca5llGbpI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tylODKyca5llGbpI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tylODKyca5llGbpI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tylODKyca5llGbpI .error-icon{fill:#552222;}#mermaid-svg-tylODKyca5llGbpI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tylODKyca5llGbpI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tylODKyca5llGbpI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tylODKyca5llGbpI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tylODKyca5llGbpI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tylODKyca5llGbpI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tylODKyca5llGbpI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tylODKyca5llGbpI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tylODKyca5llGbpI .marker.cross{stroke:#333333;}#mermaid-svg-tylODKyca5llGbpI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tylODKyca5llGbpI p{margin:0;}#mermaid-svg-tylODKyca5llGbpI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tylODKyca5llGbpI .cluster-label text{fill:#333;}#mermaid-svg-tylODKyca5llGbpI .cluster-label span{color:#333;}#mermaid-svg-tylODKyca5llGbpI .cluster-label span p{background-color:transparent;}#mermaid-svg-tylODKyca5llGbpI .label text,#mermaid-svg-tylODKyca5llGbpI span{fill:#333;color:#333;}#mermaid-svg-tylODKyca5llGbpI .node rect,#mermaid-svg-tylODKyca5llGbpI .node circle,#mermaid-svg-tylODKyca5llGbpI .node ellipse,#mermaid-svg-tylODKyca5llGbpI .node polygon,#mermaid-svg-tylODKyca5llGbpI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tylODKyca5llGbpI .rough-node .label text,#mermaid-svg-tylODKyca5llGbpI .node .label text,#mermaid-svg-tylODKyca5llGbpI .image-shape .label,#mermaid-svg-tylODKyca5llGbpI .icon-shape .label{text-anchor:middle;}#mermaid-svg-tylODKyca5llGbpI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tylODKyca5llGbpI .rough-node .label,#mermaid-svg-tylODKyca5llGbpI .node .label,#mermaid-svg-tylODKyca5llGbpI .image-shape .label,#mermaid-svg-tylODKyca5llGbpI .icon-shape .label{text-align:center;}#mermaid-svg-tylODKyca5llGbpI .node.clickable{cursor:pointer;}#mermaid-svg-tylODKyca5llGbpI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tylODKyca5llGbpI .arrowheadPath{fill:#333333;}#mermaid-svg-tylODKyca5llGbpI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tylODKyca5llGbpI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tylODKyca5llGbpI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tylODKyca5llGbpI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tylODKyca5llGbpI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tylODKyca5llGbpI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tylODKyca5llGbpI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tylODKyca5llGbpI .cluster text{fill:#333;}#mermaid-svg-tylODKyca5llGbpI .cluster span{color:#333;}#mermaid-svg-tylODKyca5llGbpI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tylODKyca5llGbpI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tylODKyca5llGbpI rect.text{fill:none;stroke-width:0;}#mermaid-svg-tylODKyca5llGbpI .icon-shape,#mermaid-svg-tylODKyca5llGbpI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tylODKyca5llGbpI .icon-shape p,#mermaid-svg-tylODKyca5llGbpI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tylODKyca5llGbpI .icon-shape .label rect,#mermaid-svg-tylODKyca5llGbpI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tylODKyca5llGbpI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tylODKyca5llGbpI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tylODKyca5llGbpI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 最高优先级
项目级
项目级 (备选)
最低优先级
覆盖
覆盖
CLI 参数

ruff check --select F401
最终配置
pyproject.toml

tool.ruff

ruff.toml

或 .ruff.toml
Ruff 内置默认值


2.3 Formatter------Black 兼容的格式化器

2.3.1 基本使用

bash 复制代码
# 格式化当前目录
ruff format .

# 检查格式化差异 (不修改文件)
ruff format --check .

# 仅格式化指定文件
ruff format src/ tests/

# 显示差异 (类似 git diff)
ruff format --diff .

2.3.2 Ruff Formatter vs Black

python 复制代码
# ── 原始代码 ──
def process_data(items: list[int], config: dict[str, any] = None) -> dict[str, list[int]]:
    result = {}
    for item in items:
        if item > 0 and item % 2 == 0 and config and isinstance(config.get('mode'), str):
            result.setdefault(config['mode'], []).append(item * 2 + 1)
    return result

# ── Black 格式化 (line-length=88) ──
def process_data(
    items: list[int], config: dict[str, any] = None
) -> dict[str, list[int]]:
    result = {}
    for item in items:
        if (
            item > 0
            and item % 2 == 0
            and config
            and isinstance(config.get("mode"), str)
        ):
            result.setdefault(config["mode"], []).append(item * 2 + 1)
    return result

# ── Ruff format (line-length=88) ── 99.9% 相同!
# 差异仅在极端边缘情况下,Ruff 有意保持与 Black 高度兼容
特性 Black Ruff Formatter
格式化质量 ✅ 成熟 ✅ 兼容 Black
速度 2.5s (10万行) 0.03s (80x)
配置项 极少 (哲学) 同样极少
--check / --diff
Jupyter Notebook
预览样式 ✅ (--preview) ✅ (--preview)

Ruff formatter 默认兼容 Black 99.9% 的输出。如果发现不一致,请提交 issue,Ruff 团队视之为 bug。


3.1 VS Code 集成------实时反馈

3.1.1 安装扩展

bash 复制代码
# 1. 安装 Ruff VS Code 扩展
#    在 VS Code 扩展市场搜索 "Ruff" (作者: Astral Software)
#    或命令行:
code --install-extension charliermarsh.ruff

3.1.2 settings.json 配置

json 复制代码
{
    // ── 关闭其他 linter, 只用 Ruff ──
    "python.linting.enabled": false,
    "python.linting.flake8Enabled": false,
    "python.linting.pylintEnabled": false,

    // ── Ruff 配置 ──
    "[python]": {
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.formatOnSave": true,                    // 保存时自动格式化
        "editor.codeActionsOnSave": {
            "source.fixAll.ruff": "explicit",           // 保存时自动修复
            "source.organizeImports.ruff": "explicit"   // 保存时整理 import
        }
    },
    "ruff.enable": true,
    "ruff.lint.enable": true,
    "ruff.format.enable": true,

    // 可选: 将格式化方式存入 import
    // 其他选项: "ruff.lineWidth": 100
}

3.1.3 工作流效果

#mermaid-svg-NcYvjQkzWEgSiQ8y{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NcYvjQkzWEgSiQ8y .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NcYvjQkzWEgSiQ8y .error-icon{fill:#552222;}#mermaid-svg-NcYvjQkzWEgSiQ8y .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NcYvjQkzWEgSiQ8y .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NcYvjQkzWEgSiQ8y .marker.cross{stroke:#333333;}#mermaid-svg-NcYvjQkzWEgSiQ8y svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NcYvjQkzWEgSiQ8y p{margin:0;}#mermaid-svg-NcYvjQkzWEgSiQ8y .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NcYvjQkzWEgSiQ8y .cluster-label text{fill:#333;}#mermaid-svg-NcYvjQkzWEgSiQ8y .cluster-label span{color:#333;}#mermaid-svg-NcYvjQkzWEgSiQ8y .cluster-label span p{background-color:transparent;}#mermaid-svg-NcYvjQkzWEgSiQ8y .label text,#mermaid-svg-NcYvjQkzWEgSiQ8y span{fill:#333;color:#333;}#mermaid-svg-NcYvjQkzWEgSiQ8y .node rect,#mermaid-svg-NcYvjQkzWEgSiQ8y .node circle,#mermaid-svg-NcYvjQkzWEgSiQ8y .node ellipse,#mermaid-svg-NcYvjQkzWEgSiQ8y .node polygon,#mermaid-svg-NcYvjQkzWEgSiQ8y .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NcYvjQkzWEgSiQ8y .rough-node .label text,#mermaid-svg-NcYvjQkzWEgSiQ8y .node .label text,#mermaid-svg-NcYvjQkzWEgSiQ8y .image-shape .label,#mermaid-svg-NcYvjQkzWEgSiQ8y .icon-shape .label{text-anchor:middle;}#mermaid-svg-NcYvjQkzWEgSiQ8y .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NcYvjQkzWEgSiQ8y .rough-node .label,#mermaid-svg-NcYvjQkzWEgSiQ8y .node .label,#mermaid-svg-NcYvjQkzWEgSiQ8y .image-shape .label,#mermaid-svg-NcYvjQkzWEgSiQ8y .icon-shape .label{text-align:center;}#mermaid-svg-NcYvjQkzWEgSiQ8y .node.clickable{cursor:pointer;}#mermaid-svg-NcYvjQkzWEgSiQ8y .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NcYvjQkzWEgSiQ8y .arrowheadPath{fill:#333333;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NcYvjQkzWEgSiQ8y .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NcYvjQkzWEgSiQ8y .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NcYvjQkzWEgSiQ8y .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NcYvjQkzWEgSiQ8y .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NcYvjQkzWEgSiQ8y .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NcYvjQkzWEgSiQ8y .cluster text{fill:#333;}#mermaid-svg-NcYvjQkzWEgSiQ8y .cluster span{color:#333;}#mermaid-svg-NcYvjQkzWEgSiQ8y div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NcYvjQkzWEgSiQ8y .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NcYvjQkzWEgSiQ8y rect.text{fill:none;stroke-width:0;}#mermaid-svg-NcYvjQkzWEgSiQ8y .icon-shape,#mermaid-svg-NcYvjQkzWEgSiQ8y .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NcYvjQkzWEgSiQ8y .icon-shape p,#mermaid-svg-NcYvjQkzWEgSiQ8y .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NcYvjQkzWEgSiQ8y .icon-shape .label rect,#mermaid-svg-NcYvjQkzWEgSiQ8y .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NcYvjQkzWEgSiQ8y .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NcYvjQkzWEgSiQ8y .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NcYvjQkzWEgSiQ8y :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Ctrl+S 保存文件
Ruff Lint

实时诊断
Ruff Fix

自动修复
Ruff Format

格式化代码
Ruff 整理

import 排序
编辑器内显示

波浪线 + 快速修复
代码自动清理
格式统一
import 有序


3.2 Pre-commit 集成------提交前自动检查

3.2.1 配置

yaml 复制代码
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.6.0                    # 使用最新版本
    hooks:
      # Linter: 检查并修复
      - id: ruff
        args: [--fix, --exit-non-zero-on-fix]
        types_or: [python, pyi]

      # Formatter: 格式化
      - id: ruff-format
        types_or: [python, pyi, jupyter]
bash 复制代码
# 安装 pre-commit hooks
pip install pre-commit
pre-commit install

# 手动对所有文件运行
pre-commit run --all-files

# 之后每次 git commit 会自动触发:
# > ruff.....................................................................Passed
# > ruff-format............................................................Passed

3.2.2 进阶:仅在变更文件上运行

yaml 复制代码
# .pre-commit-config.yaml (高性能版)
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.6.0
    hooks:
      - id: ruff
        args: [--fix]
        # 不传文件参数,ruff 自动处理暂存区文件

      - id: ruff-format

4.1 CI/CD 集成------门禁检查

4.1.1 GitHub Actions

yaml 复制代码
# .github/workflows/lint.yml
name: Lint

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

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

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install Ruff
        run: pip install ruff

      - name: Lint (不修复, 只检查)
        run: ruff check --output-format=github .

      - name: Format check (检查格式差异)
        run: ruff format --check --diff .
        # --output-format=github 使结果以 GitHub Annotation 显示

4.1.2 GitLab CI

yaml 复制代码
# .gitlab-ci.yml
ruff:
  image: python:3.11
  script:
    - pip install ruff
    - ruff check --output-format=gitlab .
    - ruff format --check --diff .
  only:
    - merge_requests
    - main

4.1.3 仅检查变更文件------加速 CI

bash 复制代码
# 在 CI 中仅 lint 变更的文件 (相比 PR base)
git diff --name-only --diff-filter=ACMR origin/main...HEAD \
  -- '*.py' '*.pyi' \
  | xargs ruff check

4.2 迁移指南------从传统工具到 Ruff

4.2.1 从 Flake8 迁移

bash 复制代码
# Step 1: 生成 Ruff 配置 (读取现有 .flake8 配置)
ruff config

# Step 2: 对比 Ruff 和 Flake8 的检查结果
ruff check . > ruff-report.txt
flake8 . > flake8-report.txt
diff ruff-report.txt flake8-report.txt

# Step 3: 移除 Flake8 及其插件
pip uninstall flake8 flake8-bugbear flake8-simplify \
    flake8-comprehensions flake8-print pep8-naming

# Step 4: 安装 Ruff
pip install ruff

# Step 5: 更新 pyproject.toml

4.2.2 规则映射表

Flake8 插件 Ruff 前缀 覆盖率
pyflakes F 100%
pycodestyle E, W 99%
flake8-bugbear B 95%
flake8-simplify SIM 99%
flake8-comprehensions C4 99%
flake8-print T20 100%
pep8-naming N 97%
flake8-annotations ANN 90%
flake8-docstrings D 90%
flake8-pytest-style PT 98%
pylint PL(部分) ~60%

4.2.3 从 isort + Black 迁移

bash 复制代码
# 移除旧工具
pip uninstall black isort

# Ruff format 替代 Black
# 之前: black --check --diff .
# 之后: ruff format --check --diff .

# Ruff lint 替代 isort
# 之前: isort --check-only --diff .
# 之后: ruff check --select I --diff .

4.2.4 pyproject.toml 迁移对照

toml 复制代码
# ── 旧配置 ──
[tool.black]
line-length = 100
target-version = ["py311"]

[tool.isort]
profile = "black"
line_length = 100
known_first_party = ["myproject"]

[tool.flake8]
max-line-length = 100
extend-ignore = ["E203"]
toml 复制代码
# ── 新配置 (Ruff) ──
[tool.ruff]
line-length = 100
target-version = "py311"

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

5.1 进阶技巧

5.1.1 忽略特定行

python 复制代码
# 忽略单行
import unused_module  # noqa: F401

# 忽略特定规则
x = "very long string that exceeds the line length limit..."  # noqa: E501

# 忽略整段代码
# ruff: noqa: F841, E501
def experimental():
    x = 1  # 不会报告 F841
    y = very_long_function_name(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)  # 不会报告 E501
# ruff: noqa: F841, E501

5.1.2 仅对特定文件启用/禁用规则

toml 复制代码
[tool.ruff.lint.per-file-ignores]
# CLI 脚本中允许 print
"cli.py" = ["T201"]
"manage.py" = ["T201"]

# 测试文件更宽松
"tests/**/*.py" = [
    "PLR2004",  # 魔数
    "S101",     # assert (测试中正常)
    "ARG001",   # 未使用函数参数 (fixture 中用)
]

# Django migrations 不使用 lint
"**/migrations/*.py" = ["ALL"]

# Notebook 文件中允许 print
"*.ipynb" = ["T201"]

5.1.3 自定义规则忽略模式

toml 复制代码
[tool.ruff.lint]
# 允许某些变量名的未使用导入 (如 typing 的 TYPE_CHECKING)
ignore-init-module-imports = true

# 不检查赋值表达式中未使用的变量
# a = [x for x in range(10) if x > 5]  ← x 被正常使用
dummy-variable-rgx = "^_+|^(_$|unused_)"  # _开头的变量不报告

[tool.ruff.lint.flake8-type-checking]
# 强制将 typing-only import 移入 TYPE_CHECKING
strict = true

5.1.4 Ruff 导出规则配置

bash 复制代码
# 将当前配置导出为配置文件
ruff check --show-settings

# 生成建议的 pyproject.toml
ruff config --format pyproject

# 查看某个文件上应用了哪些规则
ruff check --show-files file.py

5.2 性能调优

5.2.1 多层级缓存

bash 复制代码
# Ruff 自动缓存结果到 ~/.cache/ruff/
# 第二次运行几乎瞬时完成

# 查看缓存位置
ruff check --show-files . | head

# 清除缓存
ruff clean

# CI 中使用缓存 (GitHub Actions)
# .github/workflows/lint.yml
- uses: actions/cache@v4
  with:
    path: ~/.cache/ruff
    key: ruff-${{ hashFiles('pyproject.toml') }}-${{ github.sha }}
    restore-keys: ruff-${{ hashFiles('pyproject.toml') }}-

5.2.2 使用 --preview 模式

bash 复制代码
# --preview 启用尚未稳定的新规则
ruff check --preview .
ruff format --preview .

# pyproject.toml 中设置
[tool.ruff.lint]
preview = true

5.3 实战:新项目 Ruff 配置方案

toml 复制代码
# ── 最小生产级配置 ──
[tool.ruff]
target-version = "py311"
line-length = 100
extend-exclude = [
    ".git",
    ".venv",
    "build",
    "dist",
    "migrations",
    "node_modules",
    "__pycache__",
]

[tool.ruff.lint]
select = [
    "F",      # Pyflakes: 基础错误检测
    "E", "W", # pycodestyle: 代码风格
    "I",      # isort: import 排序
    "UP",     # pyupgrade: 语法现代化
    "B",      # bugbear: 常见陷阱
    "SIM",    # flake8-simplify: 简化代码
    "TCH",    # 类型检查导入
    "T20",    # flake8-print: 防止遗留 print
    "RUF",    # Ruff 专有规则
    "C4",     # comprehensions: 推导式优化
    "N",      # pep8-naming: 命名规范
]

ignore = []
fixable = ["ALL"]
unfixable = []

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

[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "parents"

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
docstring-code-format = true

5.4 常见问题与排障

5.4.1 问题排查流程

#mermaid-svg-1g24HvsXVnzfIJNL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1g24HvsXVnzfIJNL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1g24HvsXVnzfIJNL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1g24HvsXVnzfIJNL .error-icon{fill:#552222;}#mermaid-svg-1g24HvsXVnzfIJNL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1g24HvsXVnzfIJNL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1g24HvsXVnzfIJNL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1g24HvsXVnzfIJNL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1g24HvsXVnzfIJNL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1g24HvsXVnzfIJNL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1g24HvsXVnzfIJNL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1g24HvsXVnzfIJNL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1g24HvsXVnzfIJNL .marker.cross{stroke:#333333;}#mermaid-svg-1g24HvsXVnzfIJNL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1g24HvsXVnzfIJNL p{margin:0;}#mermaid-svg-1g24HvsXVnzfIJNL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1g24HvsXVnzfIJNL .cluster-label text{fill:#333;}#mermaid-svg-1g24HvsXVnzfIJNL .cluster-label span{color:#333;}#mermaid-svg-1g24HvsXVnzfIJNL .cluster-label span p{background-color:transparent;}#mermaid-svg-1g24HvsXVnzfIJNL .label text,#mermaid-svg-1g24HvsXVnzfIJNL span{fill:#333;color:#333;}#mermaid-svg-1g24HvsXVnzfIJNL .node rect,#mermaid-svg-1g24HvsXVnzfIJNL .node circle,#mermaid-svg-1g24HvsXVnzfIJNL .node ellipse,#mermaid-svg-1g24HvsXVnzfIJNL .node polygon,#mermaid-svg-1g24HvsXVnzfIJNL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1g24HvsXVnzfIJNL .rough-node .label text,#mermaid-svg-1g24HvsXVnzfIJNL .node .label text,#mermaid-svg-1g24HvsXVnzfIJNL .image-shape .label,#mermaid-svg-1g24HvsXVnzfIJNL .icon-shape .label{text-anchor:middle;}#mermaid-svg-1g24HvsXVnzfIJNL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1g24HvsXVnzfIJNL .rough-node .label,#mermaid-svg-1g24HvsXVnzfIJNL .node .label,#mermaid-svg-1g24HvsXVnzfIJNL .image-shape .label,#mermaid-svg-1g24HvsXVnzfIJNL .icon-shape .label{text-align:center;}#mermaid-svg-1g24HvsXVnzfIJNL .node.clickable{cursor:pointer;}#mermaid-svg-1g24HvsXVnzfIJNL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1g24HvsXVnzfIJNL .arrowheadPath{fill:#333333;}#mermaid-svg-1g24HvsXVnzfIJNL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1g24HvsXVnzfIJNL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1g24HvsXVnzfIJNL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1g24HvsXVnzfIJNL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1g24HvsXVnzfIJNL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1g24HvsXVnzfIJNL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1g24HvsXVnzfIJNL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1g24HvsXVnzfIJNL .cluster text{fill:#333;}#mermaid-svg-1g24HvsXVnzfIJNL .cluster span{color:#333;}#mermaid-svg-1g24HvsXVnzfIJNL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1g24HvsXVnzfIJNL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1g24HvsXVnzfIJNL rect.text{fill:none;stroke-width:0;}#mermaid-svg-1g24HvsXVnzfIJNL .icon-shape,#mermaid-svg-1g24HvsXVnzfIJNL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1g24HvsXVnzfIJNL .icon-shape p,#mermaid-svg-1g24HvsXVnzfIJNL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1g24HvsXVnzfIJNL .icon-shape .label rect,#mermaid-svg-1g24HvsXVnzfIJNL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1g24HvsXVnzfIJNL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1g24HvsXVnzfIJNL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1g24HvsXVnzfIJNL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 确实没有错误
规则未启用
文件被 exclude
极少数情况
配置差异
版本不一致
缓存问题
ruff check 没有输出?
✅ 代码质量好!
检查 pyproject.toml 的 select 字段
检查 exclude 和 extend-exclude
ruff format 和 Black 输出不同?
升级到最新版 Ruff
对比 line-length / quote-style 设置
CI 中 ruff 报错但本地不报?
锁定 ruff 版本: pip install ruff==0.6.x
ruff clean && ruff check .

5.4.2 常见误报与处理

python 复制代码
# 误报 1: TYPE_CHECKING 导入
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from myapp.models import User  # Ruff: F401 unused import
# 解决: 启用 TCH 规则, Ruff 会自动理解 TYPE_CHECKING

# 误报 2: @override 装饰器
from typing import override
class Child(Parent):
    @override
    def method(self): ...  # 如果工具不能识别 override → F811
# 解决: target-version >= "py312" 时自动识别

# 误报 3: dataclass 的 __init__
from dataclasses import dataclass
@dataclass
class Config:
    name: str = "default"  # Ruff: B008 mutable default in function
# 解决: Ruff 识别 dataclass, 不会误报 (0.3.x+)

5.5 小结

知识点 掌握程度 核心要点
Ruff 定位 掌握 Rust 编写的极速 Python linter + formatter,替代 Flake8/Black/isort
安装使用 熟练 pip install ruffruff check --fix
规则体系 掌握 700+ 规则,按前缀分类 (F/E/I/UP/B/SIM/PL...)
pyproject.toml 配置 熟练 select/ignore/per-file-ignores 三段式管理
Formatter 掌握 ruff format --check --diff .,兼容 Black 99.9%
VS Code 集成 掌握 保存时自动 lint + fix + format + import 整理
Pre-commit 掌握 提交前自动检查,零等待
CI/CD 掌握 GitHub Actions / GitLab CI 一行安装即可
迁移 掌握 Flake8→Ruff 规则映射表,配置一键转换
进阶技巧 理解 行级忽略、per-file-ignores、缓存优化

推荐资源

相关推荐
happylifetree2 小时前
Python014-第二章13.数据容器-tuple案例
python
茉莉玫瑰花茶3 小时前
LangGraph 其他核心能力 [ 3 ]
python·ai
AI玫瑰助手3 小时前
Python函数:递归函数的定义与阶乘案例实现
开发语言·python·信息可视化
武子康3 小时前
调查研究-155 Open-LLM-VTuber 本地部署与互动实战指南
人工智能·python·深度学习·ai·数字人
北漂人Java3 小时前
Pycharm配置Miniconda教程
python·pycharm
CTA量化套保3 小时前
量化程序 while True 一直跑 CPU 很高:天勤降频与字段过滤
python·区块链
copyer_xyf3 小时前
Python 内存分析:从栈和堆理解对象引用
前端·后端·python
大蚂蚁2号3 小时前
深度剖析Python全局解释器锁(GIL):原理、瓶颈与终极破局方案
python
高洁013 小时前
打造行业知识图谱三步走
python·深度学习·数据挖掘·知识图谱