news 2026/10/23 3:39:27

VSCode Python代码格式化:Ruff、Black与保存即格式化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
VSCode Python代码格式化:Ruff、Black与保存即格式化

1. 为什么格式化这件事值得认真配置一次

写 Python 的人大概都经历过这样的场景:接手一个老项目,打开某个文件,缩进是 4 个空格和 Tab 混着的,行尾有分号,字符串引号一半单一半双,函数之间空行数量全凭心情。你花十分钟改完一个函数,git diff 里却显示改了三百行。这种痛感,只有真正维护过别人代码的人懂。

代码格式化工具要解决的就是这个问题。它把"代码长什么样"从人的主观判断变成一个可执行的确定性程序:所有人保存文件的那一刻,代码自动变成同一个样子,评审的时候再也不用为空格数量吵架。VSCode 作为目前使用最广的编辑器之一,和 Python 格式化工具体的集成已经非常成熟,但配置这件事本身有个特点——上手十分钟,配好要踩坑。工具链更新快,Black、Ruff、isort、autopep8 各自定位不同,VSCode 的settings.json、pyproject.toml、扩展默认值之间的优先级又容易打架,很多人配完之后发现"保存没反应"或者"格式化结果和命令行不一致"。

这篇内容就是围绕这件事展开的。我会从为什么要选某个工具、各工具的能力边界讲起,然后给出一套可以直接抄的 VSCode 配置,再聊速度对比、迁移路径、和 pre-commit、CI 的联动,最后把我和身边同行踩过的坑整理成速查表。适合两类人看:一类是刚把 VSCode 当成主力编辑器、想让保存即格式化的新手;另一类是团队里负责统一代码风格、正在纠结要不要从 Black 切到 Ruff 的人。全部配置都经过实际运行验证,参数和路径可以按自己项目调整。

2. 工具选型的底层逻辑:Black、Ruff、isort 各管什么

2.1 先把"格式化"和"导入排序"分开看

很多人一上来就问"Black 和 Ruff 哪个好",这个问题本身有点问题,因为两者在能力范围上不完全对等。Black 是纯格式化器,它只关心代码的排版:缩进、换行、括号位置、字符串引号、尾随逗号。它有一个非常鲜明的立场——几乎没有配置项,官方说法是"你可以有的意见就是没有意见"。这个设计初看很霸道,实际用起来是优点:团队里没人能通过改配置把自己的风格偏好塞进来。

Ruff 定位是"极快的 Python linter 加格式化器"。它最早是作为 Flake8 的替代品出现的,后来逐步吃掉了 isort、pyupgrade、部分 pylint 的规则,再到 0.1 版本之后正式提供ruff format子命令,对标 Black 的格式化能力。它的核心卖点是用 Rust 写的,速度快一个数量级,并且把 lint 和 format 收进同一个二进制。

isort 是专门排 import 的。它处理的是"标准库、第三方库、本地模块"三段式分组、组内字母序、from x import y里名字的排序。Black 不管这个,Ruff 通过I规则集可以完整替代它。

所以三者关系是:格式化(排版)这一层,Black 和ruff format二选一;导入排序这一层,isort 和ruff的I规则二选一。混用可以,但要清楚谁负责什么,否则会出现两个工具互相改对方结果、保存一次代码变两次的诡异现象。

2.2 我为什么建议新项目直接用 Ruff

选型的时候我一般看三个维度:速度、维护成本、生态兼容度。做个直观对比,下面这张表是几个工具在中等规模项目(大约 800 个 Python 文件)上的粗略表现,数字来自本机实测,不同机器会有差异,但量级关系稳定:

工具职责单次全量耗时(粗略)配置复杂度和 Black 格式兼容
Black格式化8 到 12 秒极低,几乎无配置基准
ruff format格式化0.2 到 0.5 秒低,配置集中在 pyproject高度兼容,少量差异
isort导入排序3 到 5 秒中,配置项较多需与 Black 协同配置
ruff check --fixlint 加导入排序0.1 到 0.3 秒中,规则集选择需要理解不涉及

这个差距在实际开发中的体感是:Black 格式化一个大文件会有可感知的停顿(半秒左右),Ruff 基本是瞬时的。VSCode 的"保存时格式化"是个高频动作,一天的保存次数可能上千次,每次省 300 毫秒,累积起来就是几分钟的注意力中断。当然这只是体验层面的理由,更实际的理由是:Ruff 一个工具同时管 lint、导入排序、格式化,配置文件只有一份,CI 里只需要装一个依赖,团队让他人上手的成本低很多。

那 Black 还有没有必要用?有。存量项目、对格式极度敏感的项目、以及需要和上游开源项目保持一致的场景,Black 依然是最稳妥的选择。它的格式化结果更"保守",社区沉淀时间长,边界情况处理得更成熟。另外有些团队已经在 Black 上跑了几年,格式化相关的 git blame 历史很干净,切换工具会产生一次大规模 diff,这个成本要算清楚。

2.3 一个容易忽略的决策点:格式化结果要不要进 CI

配置格式化工具之前,先想清楚一个问题:格式化是"建议"还是"强制"。如果只是编辑器里保存时格式化,那团队成员用别的编辑器、或者手动改格式,就绕过去了;同样的代码在不同机器上保存,可能产生不同结果,diff 噪音还是存在。

我的做法是三层防线:编辑器层(VSCode 保存时自动格式化,给即时反馈)、提交层(pre-commit 钩子,阻断不合规提交)、CI 层(检查但通常不自动改,只报错)。编辑器和 CI 必须用同一个工具的同一套配置,否则会出现"我本地保存过了,CI 还报格式错误"这种最让人抓狂的情况。这个一致性问题后面会专门讲,它是配置翻车的第一大原因。

3. VSCode 侧的核心配置:让"保存即格式化"真正生效

3.1 扩展选择与安装顺序

VSCode 里 Python 相关的扩展现在有点乱,先理清楚装哪些:

  • Python 扩展(微软官方):提供语言服务器 Pylance、调试、环境选择。它内置了一些格式化入口,但本身不提供格式化能力。
  • Ruff 扩展(charliermarsh 那个):提供ruff check的诊断和ruff format的格式化入口。装完之后在命令面板能搜到 "Ruff: Format"。
  • Black Formatter 扩展:如果你用 Black,装这个。注意它是独立扩展,和 Python 扩展是两回事。

安装顺序其实不影响功能,但有个细节要注意:如果你同时装了 Black Formatter 和 Ruff 扩展,VSCode 会有两个格式化提供者,默认行为取决于editor.defaultFormatter的设置,没设的话可能弹窗让你选,也可能随机用其中一个。这正是很多人"保存后格式没变"的根源。

提示:装完扩展后先按Ctrl+Shift+P(macOS 是Cmd+Shift+P),输入 "Format Document With",看看列表里有几个格式化器,再决定用哪个。这个动作比翻文档快得多。

3.2 用户设置还是工作区设置

VSCode 的设置有三个层级:默认设置、用户设置(全局)、工作区设置(项目内的.vscode/settings.json)。格式化相关配置强烈建议放工作区,理由很直接:不同项目用的工具可能不同,老项目用 Black、新项目用 Ruff,如果写在用户设置里,切换项目就会互相干扰。

工作区设置的优先级高于用户设置,这个机制可以用来做"全局兜底加项目覆盖":用户设置里开editor.formatOnSave这个通用开关,具体用哪个格式化器、传什么参数,交给每个项目的.vscode/settings.json。这样新克隆一个仓库,打开就能直接用,不用问同事"你用的什么格式化"。

这里有个实践中的坑:.vscode/settings.json要不要进版本库?要进。它是团队配置的一部分,和pyproject.toml一样应该被 review。但.vscode/目录下常有个人东西(比如launch.json里的本地路径),所以常见做法是提交settings.json和extensions.json,把launch.json加进.gitignore。extensions.json里写recommendations,新同事打开项目时 VSCode 会提示装 Ruff 扩展,这一步能省很多沟通。

3.3 一套可以直接抄的 settings.json

下面是我现在新项目在用的配置,用 Ruff 做格式化和 lint。逐行都能解释为什么:

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

几个关键点逐条说。editor.defaultFormatter指定具体扩展 ID,不要留空,留空就是让 VSCode 自己猜,猜的结果不可控。editor.formatOnSave是总开关。codeActionsOnSave里的source.fixAll.ruff会执行ruff check --fix,把能自动修的问题都修掉;source.organizeImports.ruff单独管导入排序。注意这里的值写的是"explicit"而不是true,这是 VSCode 较新版本的要求,写true会有警告,语义是"只在显式保存时执行,不在自动保存时执行",避免自动保存频繁触发全量修复。

editor.rulers设成 88 是配合 Black 和 Ruff 默认的行宽。这个数字要和pyproject.toml里的line-length对齐,否则编辑器里显示一条竖线在 88 列,实际格式化按 100 列来,看着就难受。

files.trimTrailingWhitespace和files.insertFinalNewline是编辑器层的兜底,虽然格式化器也会处理,但这两个对非 Python 文件同样有效,属于零成本的好习惯。

如果你用 Black,把[python]那一段换成:

{ "[python]": { "editor.defaultFormatter": "ms-python.black-formatter", "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.organizeImports": "explicit" } } }

导入排序这里就得靠 isort 扩展或者 Ruff 的 lint 能力来补了,因为 Black 自己不管 import 顺序。这就是前面说的"混用要清楚谁管什么"。

3.4 pyproject.toml 里的对应配置

VSCode 的 settings 只管"用哪个工具、什么时候触发",工具自己的行为由项目配置文件决定。Ruff 的配置集中写在pyproject.toml:

[tool.ruff] line-length = 88 target-version = "py311" exclude = ["migrations", "build", ".venv"] [tool.ruff.lint] select = ["E", "F", "I", "UP", "B", "SIM"] ignore = ["E501"] [tool.ruff.format] quote-style = "double" indent-style = "space" skip-magic-trailing-comma = false

line-length = 88是 Black 的默认值,保持一致可以让两个工具的产出接近。target-version建议明确写出来,Ruff 会据此决定哪些语法可以自动升级(比如把旧式格式化字符串提示成 f-string),不写的话它从文件里的语法特征推断,偶尔会保守。select里"I"就是导入排序规则,这行配置的等价物就是 isort;"E501"在ignore里是因为行宽已经由格式化器负责了,lint 再报一遍是重复噪音,这个取舍很多人不知道,导致编辑里一堆波浪线。

注意 Ruff 较新版本把 lint 和 format 的配置拆成了[tool.ruff.lint]和[tool.ruff.format],老的[tool.ruff]下直接写select会报弃用警告。升级 Ruff 之后如果配置报错,先看这个。

4. 完整实操流程:从零配到一个能跑的样板

4.1 环境准备与版本确认

先确认几个版本,版本不匹配是配置失效的常见原因:

python --version # 建议 3.10 以上 ruff --version # 建议 0.6 以上,0.4 之前 format 子命令还不稳定

Ruff 通过 pip 安装:pip install ruff,或者用uv tool install ruff之类的隔离方式。装完之后必须确认 VSCode 用的是哪个 Python 环境:命令面板执行 "Python: Select Interpreter",选到项目虚拟环境里那个。Ruff 扩展默认会在工作区找ruff可执行文件,找不到会提示,这时可以在 settings 里显式指定:

{ "ruff.importStrategy": "fromEnvironment", "ruff.interpreter": ["${workspaceFolder}/.venv/bin/python"] }

interpreter这个配置项在 Windows 和 macOS/Linux 上路径不同(Windows 是.venv\Scripts\python.exe),跨平台团队要注意这个差异,或者干脆把这个路径排除在提交之外,让大家各自配本地路径,只提交importStrategy。

4.2 建立基准:先格式化一次全量代码

配置之前先做一件事:在干净的工作分支上,对全项目跑一次全量格式化,单独提交。这一步的意义是把"纯格式变更"和"业务变更"分开,否则后续任何一次业务提交里都会混着大量格式 diff,review 的人根本看不出逻辑改动。

git checkout -b chore/format-baseline ruff format . ruff check --fix --select I . git add -A git commit -m "chore: apply ruff format baseline"

全量格式化之后大概率有几百个文件被改。这个提交要让团队里的所有人都知道,因为所有人本地分支合并上来都会有冲突。经验做法是:选一个业务需求空窗期(比如周五下午),提前一天通知,格式化当天大家只做小改动,合并完再继续。冲突解决的原则是"格式冲突直接接受格式化的结果,业务逻辑冲突手工处理",这个规则提前说清楚能省掉很多来回。

4.3 逐文件验证保存格式化

全量基线建好之后,验证单文件行为。打开任意一个.py文件,故意把缩进改成两个空格、在行尾加几个空格,然后Ctrl+S。预期结果是缩进恢复成四个空格、行尾空格被清掉。如果没反应,按顺序排查三件事:

  1. 右下角状态栏看当前文件的语言模式是不是 "Python",有时候被识别成 "Plain Text",格式化器不会触发。
  2. 命令面板执行 "Format Document",看是否弹窗提示"没有安装格式化程序",这通常意味着扩展没装或未启用。
  3. 检查输出面板选 "Ruff",看有没有报错,配置语法错误会让整个扩展静默失效。

这三步覆盖了九成以上的"保存不格式化"问题。剩下的一成通常是保存方式的问题:VSCode 的"自动保存"(files.autoSave)和"保存时格式化"是两套逻辑,codeActionsOnSave里写"explicit"就是为了避免自动保存时频繁触发修复动作导致卡顿,如果你希望自动保存也格式化,那需要另外调editor.formatOnSaveMode,但一般不建议,体感很糟。

4.4 参数选择:行宽、引号、尾随逗号的取舍

这几个参数看起来琐碎,实际影响最大,因为它们是 diff 噪音的主要来源。

行宽(line-length):Black 和 Ruff 默认都是 88。这个数字不是随便定的,它来自 Black 作者对"在不影响可读性的前提下屏幕能放几列代码"的统计,考虑到左右分栏和 diff 视图。如果团队都习惯宽屏单栏,可以调到 100 或 120,但一旦定了就不能改,改一次就是全项目 diff。我的建议是能不调就不调,88 是生态里兼容性最好的值,很多开源库的配置也是 88,复制粘贴代码进来不用重排。

引号风格(quote-style):double是 Black 系的默认。Ruff 提供了quote-style = "single"的选项,但选 single 之后要注意和 Black 的兼容性会变差,如果项目里还有 Black 的 CI 检查,两边会打架。纯 Ruff 项目倒是随意,看团队习惯。

尾随逗号(skip-magic-trailing-comma):这个配置控制的是"当调用参数被拆成多行时,是否因为最后有个逗号就强制保持多行"。设成false(默认,即不跳过 magic trailing comma)意味着:你写了多行加尾随逗号,格式化器就保持多行;你删掉逗号,它可能压缩成一行。这个行为在多参数函数调用时很好用,想强制多行就在最后加个逗号,格式化器会尊重你。理解了这个机制,你就知道怎么"手动控制"格式化器的展开了。

4.5 和 pre-commit 打通

编辑器层只对"在 VSCode 里保存"生效,命令行git commit或者别的编辑器绕过它。加一层 pre-commit:

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

rev这个版本号必须和本地安装的 Ruff 版本大致对齐。pre-commit 会自己下载指定版本的 Ruff 到独立环境里跑,如果本地是 0.6 而钩子是 0.4,两边格式化结果可能有差异,表现就是"本地保存没问题,提交时被改了"。这种问题很难查,因为报错信息只是说文件被修改。

钩子执行失败时 git commit 会被阻断,此时文件已经被格式化过了,git add之后重新 commit 即可。这个流程第一次遇到会有点懵,习惯了就好,它保证了进仓库的代码一定是格式化过的。

注意:pre-commit 钩子在首次运行时需要下载环境,可能卡住一两分钟,这不是 bug。团队新人第一次提交时经常以为是网络问题,提前说一句能省很多困惑。

5. 从 Black 迁移到 Ruff:真实操作路径和踩过的坑

5.1 迁移之前先做兼容性评估

Black 和ruff format的格式化结果高度接近但不是完全相同。差异集中在少数边界情况:字符串拼接的换行处理、某些复杂表达式的括号放置、注释位置。Ruff 官方给了一个专门的做法:用ruff format --diff在存量代码上跑一遍,看有多少处会和当前格式不同。

ruff format --diff . | head -100 ruff format --diff . | grep -c "^---"

先看几百行 diff 长什么样,心里有数。如果项目已经用 Black 格式化过,差异通常只有总文件的 1% 到 5%。这个 diff 量决定了迁移成本:差异小,一次性切换;差异大(比如项目里有大量长字符串或复杂链式调用),可以先在 CI 里允许两种格式并存一段时间,或者接受一次大 diff。

5.2 分步迁移的具体做法

我推荐的顺序是这样的,每一步都是独立提交,方便回滚:

  1. 先切 lint:把 flake8、isort、pyupgrade 这些 lint 工具换成 Ruff 的ruff check,格式化仍然用 Black。这一步风险最低,因为 lint 报错是可见的,改不改可以逐个判断。
  2. 再切格式化:Black 换成ruff format。切换前跑一次ruff format --diff存档,切换后跑一次全量格式化,单独提交。
  3. 清理依赖:从requirements-dev.txt里删掉 black、flake8、isort,加上 ruff。同时更新 pre-commit 配置和 CI 脚本。
  4. 更新编辑器配置:改.vscode/settings.json的defaultFormatter,让扩展推荐列表加上 Ruff,删掉 Black Formatter 的推荐。

第 2 步之后要特别验证一件事:CI 里的格式检查是不是真的在用 Ruff。很多项目 CI 脚本里写的是black --check .,切换工具时只改了本地配置忘了改 CI,结果本地保存格式化好的代码推上去 CI 报错,报的还是 Black 的错误。这种低级错误我见过不止一次,检查清单里应该有一条"全局搜索项目里的 black 关键字"。

5.3 迁移后必须保留的配置项

切到 Ruff 之后有些 Black 的行为需要显式配置才能保持,容易漏:

Black 行为Ruff 对应配置说明
行宽 88line-length = 88默认值一致,但如果 Black 时改过要同步
双引号quote-style = "double"默认就是 double
尾随逗号保留skip-magic-trailing-comma = false默认 false,若 Black 时用了--skip-magic-trailing-comma要注意
单行 if 不合并无直接对应Ruff 更倾向于保持原样,这点反而更保守
目标版本target-version = "py311"Black 从 pyproject 的 requires-python 推断,Ruff 建议显式写

最后一行值得多说一句。Black 会读pyproject.toml里的requires-python来推断目标版本,Ruff 也支持这个推断,但推断失败时会退回到一个保守的默认值,表现就是某些能升级的语法它不敢升。显式写target-version可以避免这种不确定性。

5.4 团队协作中的推行技巧

工具切换是人的问题,不是技术问题。我踩过的坑里,最难的不是配置,是让团队接受一次几百文件的 diff。几个实操经验:

提前准备一份"为什么换"的一页纸。别写长篇大论,就三点:格式化速度提升到什么程度(给具体数字)、依赖从几个减到一个、配置从几份合成一份。工程师对速度和依赖数量的敏感度远高于"工具更现代"这种说法。

把全量格式化和业务分支错开。前面提过,补一句细节:格式化提交要放在业务分支合并之后、新需求开始之前。如果团队用 trunk-based 开发,那就选一个大家都在的低活跃时段,格式化完立刻通知。

给不愿意换的人留退路。有人就是习惯 Black,可以让他本地继续用,但 pre-commit 和 CI 用 Ruff 卡住。听起来矛盾,实际可行:ruff format和 Black 的产出在 95% 以上的代码上一致,剩下的差异由 pre-commit 兜底修正。这不是理想状态,但比强行要求所有人同一天切换要好。

观察一周再删旧工具。切完之后别急着删 Black 的依赖和配置,留一周。这一周里如果发现 Ruff 有某个行为团队实在不能接受,回滚成本最低。一周后再清理,同时更新 README 里的开发说明——这一步最容易被忘,新人照着旧文档装 Black,装完发现没用,浪费时间。

6. 常见问题与排查速查表

6.1 保存不格式化:按这个顺序查

现象可能原因排查动作
保存完全没反应语言模式不对右下角确认是 Python
保存没反应没设 defaultFormatter命令面板 "Format Document With" 看列表
弹窗让选格式化器装了多个格式化扩展显式设editor.defaultFormatter
只格式化了部分文件有语法错误看输出面板 Ruff 日志
格式化后又被改回去两个格式化器打架禁用其中一个扩展
保存很卡codeActionsOnSave设了 true改成"explicit"

倒数第二条值得展开。"格式化后又被改回去"的典型表现是:按保存,代码变了一下,再按保存,又变回去,来回横跳。原因是两个格式化提供者(比如 Black 和 Ruff)对同一段代码有不同意见,VSCode 每次保存调用其中一个,另一个的"保存时修复"又把它改回来。解决办法只有一个:只留一个格式化器。在扩展面板里禁用另一个,或者在 settings 里明确指定,别依赖默认行为。

6.2 本地和 CI 结果不一致

这是最高频的求助。表现:本地保存看起来格式化好了,推上去 CI 报格式错误。原因通常有四类:

版本不一致。本地 Ruff 是 0.6.9,CI 装的是ruff最新版,或者 pre-commit 钩子 pin 的是老版本。格式化器的行为在小版本间会有调整。解决办法是把版本 pin 死:requirements-dev.txt里写ruff==0.6.9,pre-commit 的rev写同一个版本,CI 里也装这个版本。三处对齐,问题消失。

配置没被读到。Ruff 从当前工作目录向上找pyproject.toml。如果 CI 在子目录里执行命令,可能读不到根目录的配置。加--config pyproject.toml显式指定,或者确认 CI 的工作目录。

编辑器和命令行用的不是同一个可执行文件。本地可能装了多个 Ruff(系统级、虚拟环境、pipx),VSCode 用的和终端里which ruff指向的不是一个。用ruff --version在 VSCode 集成终端里跑一次,对比一下。

排除规则不一致。pyproject.toml里exclude排除了某些目录,但 VSCode 的files.exclude没同步,或者反过来。表现是某个文件本地不格式化、CI 却检查它。这个要靠 review 配置文件保证一致。

6.3 格式化破坏了代码语义的几种罕见情况

格式化器理论上不该改变语义,但有几个边界值得知道:

字符串里的隐式拼接。多行字符串用括号隐式拼接时,格式化器可能调整换行位置,虽然字符串内容不变,但如果那段字符串是 SQL 或者正则,换行位置变化可能影响可读性甚至某些场景下的行为(比如依赖行号的日志解析)。这种情况可以用# fmt: off和# fmt: on包起来,Ruff 和 Black 都支持这个注释。

类型注解里的字符串前向引用。格式化器会调整引号风格,如果代码里有"ClassName"这种字符串形式的注解,改成双引号没问题,但如果原本用的是单引号且代码里有转义,要检查一下。

注释和代码的相对位置。格式化器有时会把行尾注释挪到上一行或下一行。如果注释是给某一行特定代码的(比如# noqa),位置变了可能失效。# noqa、# type: ignore这类有语义的注释,格式化后要抽查。

提示:项目里如果有# fmt: off的区块,建议在 README 里说明为什么这块不格式化,否则后来的人看到会想"顺手格式化一下",然后引入非预期 diff。

6.4 性能相关的实际体感

Ruff 快是共识,但具体到 VSCode 保存这个场景,有几个观察:

首次打开大项目时,Ruff 扩展会做一次全量扫描,这时保存可能有一两秒延迟,之后就正常了。这个延迟和项目大小相关,几千文件的项目首次扫描可能要十几秒,扫描期间编辑器里会有诊断信息陆续出现,别慌,这是正常的。

codeActionsOnSave里同时开fixAll和organizeImports时,Ruff 会跑两遍 lint(一次修全部,一次排 import)。可以合并成只开fixAll,因为 Ruff 的I规则在fixAll里也会被执行——前提是select里包含"I"。这个小优化能减少一次全文件扫描,在大文件上体感明显。

另外,如果项目里有超长的单行文件(比如自动生成的 protobuf 或数据文件),格式化会很慢甚至卡住。这类文件应该加进exclude,别让格式化器碰。

7. 我个人的几条经验

配置这件事有个反直觉的地方:越简单的配置越稳定。我见过有人把settings.json写成两百行,每个语言单独配格式化器、每个格式化器带一堆参数,最后自己都说不清哪个生效。Ruff 的一个隐性优势就是它逼你收敛:一份pyproject.toml,一个defaultFormatter,加两行codeActionsOnSave,就完了。剩下的交给工具的默认值。

关于 Black 和 Ruff 的选择,我的实际体会是:新项目无脑 Ruff,存量项目别急着换。存量项目换工具的收益主要是速度,但代价是一次大 diff 和团队心智负担。如果团队规模小、代码量不大,这个收益其实没那么显著,Black 稳定跑了几年也是一种资产。真正该换的信号是:CI 跑得慢到影响迭代节奏、或者 lint 和格式化用的工具太杂导致配置维护成本高。

最后分享一个小技巧。迁移或者大改格式化配置之前,先在项目根目录跑一次ruff format --diff . > format-before.diff,把当前状态存下来。改完配置再跑一次生成format-after.diff,对比两份文件的差异,你能精确看到配置改动的实际影响范围。这一步比看文档猜效果靠谱得多,尤其在调line-length和skip-magic-trailing-comma这类参数时,diff 会直白地告诉你代价是多少行。养成这个习惯之后,我对格式化配置的每次改动都心里有数,不会出现"改了个参数,整个 repo 红了"的情况。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 3:39:26

桌面AI工作台:自定义指令与技能从入门到精通

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/23 3:38:31

Ubuntu+Windows双系统安装:分区、引导与故障排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/23 3:38:26

OpenCode Skills 必装合集详解:让 AI 从实习生变熟练工

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/23 3:38:22

软考网络工程师第五章:IPv4头部结构与IP分片机制备考精讲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/23 3:37:53

磁力链接与infohash:DHT索引、检索入口与实操技巧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/23 3:37:34

电机堵转保护原理与实战排查:机械、驱动器、电机三维度诊断

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华