大规模编写和 lint Python

Meta 在 Fixit 2 上的工作——一个基于 libcst、可自动修复的 Python linter——引发了更广泛的讨论:如何借助更强的工具、类型注解和自动化代码转换,让 Python 在大规模场景下可用。评论者将 Python 日益壮大的静态类型生态和各类 linter(包括 Ruff 和 Fixit)与 TypeScript、C# 等语言进行对比,争论动态语言究竟适不适合作为大型系统的基础,还是只是靠“创可贴式”工具勉强维持。另一些人则更关注实际取舍:Python 的调试便利和快速开发能力,与其性能限制、线程问题,以及真实代码库中类型注解和库质量参差不齐之间的权衡。

讨论的背景与工具

  • 线程围绕 Meta 的 Fixit 2 Python linter 展开,它建立在 libcst 之上,同时也讨论了在大规模场景下对 Python 进行 lint 和类型检查的更广泛经验。
  • Fixit 2 的一个显著特性是:lint 规则不仅能报告问题,还能自动应用代码更改。

对自动修复型 linter 的信任与工作流

  • 有些人对会自动更改代码、且超出格式化/导入范围的 linter 持谨慎态度。
  • 也有人指出,C#/.NET、ESLint 和 Rubocop 等生态里,自动修复是标准且高效的,尤其是在以下情况下:
    • 修复是在提交后或通过代码评审、并经明确接受后应用。
    • 只自动应用“安全”类别的修复。
  • 建议的工作流是:先提交,再运行自动修复,然后检查 diff。

Ruff vs Flake8 及其他 linter

  • Ruff 的优点包括:
    • 极快的速度。
    • 将格式化、lint 和导入排序整合到一个工具中。
    • 能发现一些 flake8 插件遗漏的问题。
  • 批评包括:
    • 在大型、混乱的遗留代码库上,与原始 flake8 插件的行为不一致。
    • 过去某些自动修复会引入新问题;新版本的 Ruff 已区分“安全”和“不安全”的修复。
  • 线程中的 Ruff 维护者表示:
    • 他们的目标是达到与插件相同或更好的正确性,并欢迎 bug 报告。
    • lint/fix 是迭代进行的,直到不再有可修复的问题为止。
  • 几位评论者表示,他们已在许多项目中成功采用 Ruff,且几乎没有问题。

大规模 Python:动态类型 vs 静态类型

  • 对 Python(以及类似“动态脚本语言”)是否适合大型系统,存在强烈分歧:
    • 批评者认为:大公司最终会重建静态类型和繁重工具;如今静态语言原型开发已经足够快,因此从动态语言开始是个错误。
    • 支持者认为:Python 的可选类型系统、和类型、模式匹配以及外部检查器,使其仍然可行,并且越来越“安全”。
  • 还有很长的子线程在争论术语(“动态语言”“动态类型”)和类型理论细节:递归类型(JSON)、可变参数泛型、元组拼接,以及与 TypeScript 和 Haskell 的比较。

Python 的优点与缺点

  • 支持者强调:
    • 调试容易,运行时错误清晰。
    • 语法好,适合教学。
    • 类型注解正在提高大型代码库的可扩展性。
  • 批评者则认为:
    • 就工程价值而言,Python 从来不是“最佳”工具;流行度和临时补丁式工具占了主导。
    • 性能和线程(GIL)仍然是真实的扩展限制;规避办法往往涉及子进程。

对统一工具链的需求

  • 有些人希望有一个单一工具来处理格式化、lint、排序和 pre-commit 检查,更看重一致性而不是具体风格。
  • Ruff 被视为一个有希望的候选者;其资金支持被认为可能加速朝着“单工具”一致性的方向发展,甚至可能取代当前碎片化的 pre-commit 生态。