Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 762 – 替换默认的 REPL

作者:
Pablo Galindo Salgado <pablogsal at python.org>, Łukasz Langa <lukasz at python.org>, Lysandros Nikolaou <lisandrosnik at gmail.com>, Emily Morehouse-Valcarcel <emily at python.org>
发起人:
Pablo Galindo Salgado
状态:
最终版
类型:
信息性
创建日期:
2024年10月11日
Python 版本:
3.13

目录

摘要

Python 的核心优势之一是其交互模式,也称为读取-求值-打印循环(REPL),或 Python 控制台,或 Python shell。本 PEP 描述了用 Python 编写的此功能的新实现。Python 3.13 中发布的新 REPL 旨在提供当今用户所期望的现代功能,例如多行编辑、语法高亮、自定义命令以及整体改进的交互体验。

动机

在 Python 3.12 之前,CPython 的交互式 shell 是用 C 语言编写的,作为解析器的一种特殊模式。因此,它难以维护和扩展。它依赖于 GNU readline(或等效库)的存在,以实现光标移动和历史记录跟踪等基本功能。如果没有此库编译的 Python 提供了一个功能非常有限的交互模式。另一方面,使用 readline 编译的 Python 将用户输入相关的决策和配置外包,这使得扩展它变得困难。

这种复杂性阻碍了贡献,并使实现新功能变得具有挑战性。结果,CPython 交互式 shell 几乎没有变化,落后于用户对现代替代品的需求。

许多用户期望的现代 REPL 功能在以前的版本中都不存在。这些功能的一些示例包括多行编辑和历史记录、自定义命令、语法高亮或符合人体工程学的复制和粘贴处理。这些功能的缺乏极大地影响了 CPython 许多用户群的用户体验,特别是在用户无法控制依赖项且无法安装自己的包的环境中。这对于学习该语言的用户和教育者来说尤其普遍。

使用 C 语言实现来解决此类问题需要复杂的变通方法,例如命令的 AST 匹配,这将给代码库增加过高的复杂性。

通过用 Python 编写的新 REPL,我们正在解决这些限制,同时使 CPython 的交互体验更符合现代期望和功能。

基本原理

用 Python 而不是 C 实现新的 REPL,显著降低了贡献者的门槛。这一变化使 REPL 更容易测试、验证和修改,从而增加了社区参与度和加快了功能开发。代码库的可访问性提高有望带来一个更快发展和更响应用户需求的 REPL。

我们决定不从头开始编写 Python REPL,而是将新 REPL 的实现基于 PyREPL。这一决定是受几个关键因素驱动的。首先,开发一个在不同操作系统和终端模拟器上都能一致运行的终端应用程序是一项复杂的任务。通过采用在 PyPy 项目中经过实战考验的 PyREPL,我们可以利用现有经过验证的代码,而不是从头开始。

与 PyPy 共享 REPL 实现的代码库为两个项目带来了互惠互利。它允许共享维护工作、更快的错误修复和功能改进,这些都可以使 CPython 和 PyPy 的用户受益。这种协作可以为整个 Python 生态系统带来一个更健壮、功能更丰富的 REPL。

以前用 C 编写的 REPL 利用“readline”或“editline”库作为后端,以允许某些功能,例如导航、历史记录保存和调用、自动补全以及可配置的键盘行为。PyREPL 不使用这些库,而是直接将大多数其他功能作为 shell 的一部分实现。主要缺少的功能(输入的配置能力)被新架构的优势所弥补。这些库的配置文件(例如 inputrc)很复杂,并且包含 PyREPL 不打算实现的功能,这使得在新 shell 中透明地添加对它们的支持不可行。在 PyREPL 中使用“readline”或“editline”会由于多行编辑处理和多平台支持而变得极其复杂。

尽管这意味着现有的 readline/editline 配置将与 PyREPL 不兼容,但我们相信增强的功能和改进的可扩展性是全面的胜利。有关对自定义工作流的持续支持的讨论,请参阅“向后兼容性”。

以前的 REPL 使得正确实现自定义命令变得具有挑战性,而自定义命令是交互式 shell 的常见功能。例如,exit 命令是作为注入到全局命名空间中的自定义对象的方法调用实现的,导致了非直观的行为,当用户简单地键入 exit 时,解释器会提示他们使用所谓的正确用法 exit(),这通常会让他们感到困惑。

规范

PyREPL 作为新的私有 Python 模块 _pyrepl 实现,与当前的 C 实现并存。在其首次实现中,它引入了以下关键功能:

  1. 多行历史记录和编辑:用户可以跨多行导航和编辑其命令历史记录,从而提高了完善和重用复杂代码块的能力。

    编辑多行块时,使用四个空格自动缩进,这与 PEP 8 建议一致。当遇到以冒号结尾的行时,下一行会自动缩进,使用从包含缩进的第一行推断出的缩进模式。行以四个空格缩进,并且制表符会转换为空格。

    用户可以使用 箭头访问命令历史记录。在多行条目中,箭头键在移动到下一个历史记录条目之前,会在块内逐行导航。 箭头反向工作,从较旧的条目导航到最近的条目。

    历史记录可以通过使用自定义子字符串查询向前(使用 Ctrl+S)和向后(使用 Ctrl+R)搜索。它也可以通过在 shell 行中输入前缀并使用 PageUp 和 PageDown 键进行前缀查询搜索。

  2. 复制和粘贴:在支持的终端模拟器中,PyREPL 会发现并使用带括号的粘贴功能。这允许透明地粘贴代码块而无需立即执行或无效的自动缩进。

    对于不支持此模式的终端模拟器,实现了一个专用的粘贴模式,以便轻松插入多行代码片段,而不会触发立即执行或缩进问题。

    用户通过按 F3 键进入手动粘贴模式。提示符从 >>> 变为 (paste),用户可以在其中粘贴剪贴板内容或根据需要手动输入。内容准备好后,按 F3 退出粘贴模式。然后,按 Enter 执行该块。

    用户在使用粘贴模式时可以在单个输入上输入多个命令,这将有助于从其他源粘贴代码。

    要复制不带前导命令提示符且不带命令输出的代码块,用户可以通过 F2 键进入历史视图。此模式使用寻呼机显示已执行命令的历史记录,不带提示符和输出。

  3. 通过 F1 获取帮助。

    可以通过自定义命令 help(见下文)或通过 F1 键访问标准帮助模块。按 F1 进入帮助模式。完成后,按 F1 或标准命令(qquitexit)退出。

    浏览交互式帮助不会保留命令历史记录。

  4. 自定义命令:REPL 以更自然、更用户友好的方式支持实现自定义命令,例如 exit,避免了当前函数调用变通方法。

    最初的自定义命令列表包括:

    • exit
    • quit
    • copyright
    • help
    • clear

    只要与可访问范围内的变量没有名称冲突,命令就可用。例如,在赋值 exit = 1 之后,变量将优先于 PyREPL 命令。在这种情况下,del exit 将消除冲突,命令将再次起作用。

  5. 颜色:提示符以及输出的某些元素(如异常回溯)现在已着色。可以使用标准 NO_COLOR 环境变量禁用颜色,或者通过使用标准 FORCE_COLOR 环境变量强制启用颜色。还有一个 Python 特定的环境变量,名为 PYTHON_COLORS。Python 3.13 中的初始实现不提供颜色主题的自定义。

这些功能显著增强了交互式 Python 体验,使其更符合现代开发环境和用户期望。该实现是用 Python 编写的,提供了几个优点:

  1. 更轻松的测试和验证:编写 Python 代码的测试比编写 C 代码的测试简单得多,可以直接得多,从而可以对所有现有和旧功能进行更全面的测试覆盖。
  2. 更低的贡献门槛:Python 的可访问性与 C 相比,鼓励了更多社区贡献,从而加快了功能开发和错误修复。
  3. 灵活性:Python 实现更易于扩展和修改,提高了核心开发人员和贡献者在开发新功能和改进方面的开发速度。

向后兼容性

PyREPL 的实现旨在与现有 Python 代码保持完全向后兼容性,因为旧的基本 REPL 将作为备用保留并按需提供,以防自定义工作流需要它。在由于环境限制或其他问题导致无法使用新 REPL 的情况下,它也将被使用。用户可以选择通过将环境变量 PYTHON_BASIC_REPL 设置为 1 来显式选择旧的基本 REPL。这确保了用户如果愿意,或者如果他们遇到新实现的任何问题,可以继续使用熟悉的界面和功能。

重要的是要强调,PyREPL 的引入不会删除任何现有功能。旧的基本 REPL 中 PyREPL 不具备的任何功能都保留并维护在旧的基本 REPL 中,用户可以将其用作备用。

特别是,希望继续在 inputrceditrc 文件中使用其自定义输入配置的用户可以继续使用旧的基本 REPL。

作者不期望将任何 PyREPL 功能移植到旧的基本 REPL。同样,PyREPL 中明确不计划支持 inputrceditrc。这些配置文件由“readline”和“editline”库提供和解析,它们的功能范围与 PyREPL 旨在实现的功能不匹配。

为了方便平稳过渡,提供了 清晰的文档,说明如何在 PyREPL 和旧的基本 REPL 之间切换。

这种方法确保了,虽然我们正在通过新的 REPL 引入重大改进,但我们不会对依赖当前实现的用户强制进行任何立即更改。回退机制和用户选择选项提供了一个安全网,允许逐步采用新的 REPL,同时保留所有现有功能。

安全隐患

本提案没有带来任何安全隐患。

如何教授此内容

PyREPL 的引入伴随着文档和教程。教育的重点领域将包括:

  1. 关于使用多行编辑、粘贴模式和其他新功能的详细说明。
  2. 自定义命令(现有和新命令)。
  3. 如何切换到新的 REPL,包括与以前基于 readline/editline 的配置的任何差异。

被拒绝的想法

考虑并最终拒绝了几种替代方法:

  1. 扩展当前的 C 实现:虽然这会保持最大的向后兼容性,但它被认为过于复杂,并且无法解决上面描述的基本限制。
  2. 从头开始开发一个新的 REPL:由于创建跨平台终端应用程序的复杂性以及利用现有成熟代码的愿望,这种方法被拒绝。
  3. 使用其他现有的 REPL 实现:作者研究了几种替代方案,例如 IPythonbpythonptpythonxonsh。虽然所有这些都是令人印象深刻的项目,但最终选择 PyREPL 是因为它结合了成熟度、功能集以及缺乏额外依赖。另一个关键因素是与 PyPy 的实现保持一致。

致谢

感谢 Diego Russo 为本 PEP 的草稿提供反馈。


来源:https://github.com/python/peps/blob/main/peps/pep-0762.rst

最后修改:2025-02-01 07:28:42 GMT