Ruff v0.4.0

Ruff v0.4.0

💡 原文英文,约1400词,阅读约需6分钟。
📝

内容提要

Ruff v0.4.0 发布,用自研手写递归下降解析器取代生成式解析器。新解析器速度提升逾2倍,使整体 lint 和格式化提速20-40%,并增强边缘情况控制、错误提示更清晰,为未来错误恢复和编辑器友好体验奠定基础。

🔎

延伸解读

性能提升的实际影响

Ruff v0.4.0 将解析器从生成式改为手写递归下降,解析速度提升超过2倍,进而使所有 lint 和格式化调用提速20-40%。对于大型项目,这意味着更快的 CI 反馈和编辑器响应。例如,在 home-assistant/core 上,lint 时间从约450毫秒降至64毫秒,格式化从约193毫秒降至约308毫秒(注:原文数据如此,格式化时间有所增加,但整体仍受益)。

错误信息更清晰

手写解析器能提供更具体的语法错误提示。例如,旧版可能只报“Unexpected token Newline”,新版会指出“Expected one or more symbol names after import”。这有助于开发者快速定位问题,减少调试时间。错误信息的改进是解析器控制力增强的直接体现。

为编辑器体验铺路

手写解析器为未来的错误恢复功能奠定了基础。目前 Ruff 尚未实现错误恢复,但计划在后续版本中支持:即使代码存在语法错误,也能继续解析并提供 lint 诊断和修复。这对于编辑器中的实时检查尤为重要,因为编辑过程中常出现临时语法错误。

维护性与未来优化

生成式解析器(基于 LALRPOP)在支持最新 Python 语法时遇到限制,且难以优化。手写解析器让 Ruff 团队完全控制解析过程,能更灵活地处理边缘情况(如 with 语句中的括号歧义),并便于未来针对错误恢复和性能进行深度优化。

❓

Q&A

Ruff v0.4.0 的主要更新是什么?

Ruff v0.4.0 的主要更新是用自研的手写递归下降解析器取代了原有的生成式解析器。新解析器速度提升超过2倍,使整体 lint 和格式化速度提升20-40%,并增强了边缘情况控制、错误提示更清晰,为未来的错误恢复和编辑器友好体验奠定了基础。

为什么 Ruff 要从生成式解析器切换到手写解析器?

切换原因包括:生成式解析器难以维护,受限于解析器生成器的语法支持,难以支持最新的 Python 语法;手写解析器能提供更好的错误处理和恢复控制,对编辑器友好工具至关重要;此外,手写解析器性能显著更优,且团队已清楚所需 AST 结构,并已单独维护解析器。

手写解析器带来了哪些性能提升?

手写解析器比生成式解析器快2倍以上,使所有 lint 和格式化调用速度提升20-40%。例如,在 home-assistant/core 上,lint 时间从449.9毫秒降至364.1毫秒,格式化从381.9毫秒降至307.8毫秒;在 pytorch/pytorch 上,lint 从328.7毫秒降至251.8毫秒,格式化从351.1毫秒降至274.9毫秒。

手写解析器如何改善错误提示?

手写解析器能提供更清晰的错误消息。例如,对于 `from x import`,旧提示是“Unexpected token Newline”,新提示是“Expected one or more symbol names after import”;对于 `async while test: ...`,旧提示是“Unexpected token 'while'”,新提示是“Expected 'def', 'with' or 'for' to follow 'async', found 'while'”。

Ruff 未来在解析器方面有哪些计划?

未来目标包括:实现完整的错误恢复,确保解析器能从所有语法错误中恢复;报告所有语法错误,让开发者全面了解代码问题;允许 linter 在存在语法错误时继续分析。最终目标是让 Ruff 成为快速且能容忍语法错误的一流编辑器工具。

手写解析器如何提升 Ruff 在编辑器中的使用体验?

手写解析器为错误恢复奠定了基础,使 Ruff 能在遇到语法错误时继续解析和分析代码,从而在编辑器中即使代码暂时不完整或有错误,也能提供 lint 和格式化诊断。虽然当前版本尚未实现错误恢复,但这是未来计划的一部分。

🏷️

标签

➡️

继续阅读