5.1 为什么需要 Formatter
Linter 检查"是否有问题",Formatter 则统一"如何排版"——空格、换行、引号、缩进、对齐。关键价值是消除"风格之争":团队里没人再需要争论 '单引号' 还是 "双引号",机器说了算,diff 干净清爽。
Black 是 Python 社区事实标准的格式化器,由 Python Core Dev Łukasz Langa 主导。它的口号是 "The uncompromising code formatter"——基本不可配置,强制统一风格。Ruff 的 ruff format 对齐 Black 的这套风格,并用 Rust 重写了一遍。
5.2 基本用法
$ ruff format . # 格式化当前目录所有 .py
$ ruff format app/ # 限定目录
$ ruff format foo.py # 单文件
$ ruff format --check . # 只检查不改(CI 用,非 0 = 有需要格式化的)
$ ruff format --diff . # 输出会改动的 diff
$ cat foo.py | ruff format - # 从 stdin 读
5.3 配置项
[tool.ruff.format]
quote-style = "double" # 引号:double/single/preserve
indent-style = "space" # space/tab
line-ending = "auto" # auto/lf/crlf/native/cr
skip-magic-trailing-comma = false
docstring-code-format = true # 格式化 docstring 里的代码块
docstring-code-line-length = "dynamic" # 或具体数字
5.4 Black 兼容性
ruff format 与 Black 几乎 1:1 兼容——对同一个合法 Python 文件,两者产生的输出基本一致。Ruff 官方维护了一个兼容性报告,覆盖 CPython 官方测试套件、几十个知名开源项目,绝大多数文件 0 差异。
已知少量刻意的差异(出于性能或设计原因):
- 链式函数调用的换行阈值略不同
- 极长字符串切分策略(Black 24.x 后才加入的行为)
- 某些隐含 continuation 的格式化决策
这些差异都不影响代码功能,只是排版细节。从 Black 迁到 ruff format 时,一次性跑 ruff format . 会产生一个小 commit 修正格式——这是正常且一次性的。
5.5 quote-style:引号统一
# quote-style = "double" (默认)
x = "hello"
y = 'contains "double"' # 含双引号时保留单引号,避免转义
# quote-style = "single"
x = 'hello'
# quote-style = "preserve"
# 不动引号,只管其他排版(迁移期过渡用)
5.6 Magic Trailing Comma
Black/Ruff 的一条重要规则:函数调用/列表/字典的最后一个元素若带尾逗号,强制多行展开。这是开发者表达"我想让它多行"的简单信号。
# 输入(你写的)
result = foo(
"a",
"b",
"c", # 尾逗号
)
# 输出:保持多行,因为尾逗号告诉格式化器"我要多行"
# 删掉尾逗号后
result = foo("a", "b", "c") # 单行(如果容得下)
若想关闭这一特性(回到纯机械换行):
[tool.ruff.format]
skip-magic-trailing-comma = true
5.7 Docstring 里的代码块格式化
项目如果喜欢在 docstring 里写 Example: 代码块,启用 docstring-code-format 能让 Ruff 连 docstring 内部的代码也格式化:
def add(a, b):
"""Add two numbers.
Example:
>>> add( 1 ,2 ) # 格式化前
3
>>> add(1, 2) # 格式化后
3
"""
return a + b
支持 Python doctests(>>> 前缀)和 Markdown 风格代码块(```python)。
5.8 局部禁用格式化
极少数情况下你希望某段代码"不要被格式化"(比如手工排好的大矩阵数据、特殊对齐),用 # fmt: off / # fmt: on:
# fmt: off
matrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
]
# fmt: on
# 单行版本
x = [1,2,3] # fmt: skip
5.9 与 Lint 协同
格式化和 Lint 是独立的两步,推荐顺序:先格式化(排版统一后 lint 的噪音变少),再 lint。
# 本地典型流程
$ ruff format .
$ ruff check --fix .
# CI 典型流程
$ ruff format --check .
$ ruff check .
有些规则比如 E501(行太长)在启用 formatter 之后意义不大——formatter 会自动换行,但有些长行(长字符串、长 URL)formatter 也管不了。多数项目会选择 ignore = ["E501"] 完全放手给 formatter。
5.10 小结
ruff format内置,99% Black 兼容,比 Black 快 30 倍。- 主要配置项只有 quote-style、line-length、docstring-code-format——刻意保持简单。
- CI 用
--check,本地直接ruff format .。 - 格式化和 lint 分工:format 管排版,check 管问题。