news 2026/7/3 7:16:36

Python PEP 822 提案:新增自动缩进移除的多行字符串语法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python PEP 822 提案:新增自动缩进移除的多行字符串语法

PEP 822 – 消除缩进的多行字符串(d-string)

作者:
Inada Naoki

摘要

本 PEP 提议增加一个功能,用于自动从多行字符串字面量中移除缩进。
消除缩进的多行字符串(dedented multiline strings)使用一个新的前缀“d”(“dedent”的简写),放在多行字符串字面量的开引号之前。
示例(空格用下划线_可视化):

defhello_paragraph()->str:____return d""" ________<p> __________Hello, World! ________</p> ____"""

末尾的三引号决定了要移除多少缩进。
在上面的例子中,返回的字符串将包含三行:

"____<p>\n"(四个前导空格)
"______Hello, World!\n"(六个前导空格)
"____</p>\n"(四个前导空格)

动机

在深度缩进的 Python 代码中编写多行字符串字面量时,用户面临以下选择:

  1. 接受字符串字面量的内容将左对齐。
  2. 使用多个单行字符串字面量拼接,而不是使用一个多行字符串字面量。
  3. 使用textwrap.dedent()来移除缩进。

所有这些选项在代码可读性和可维护性方面都有缺点。

  • 左对齐的多行字符串看起来不协调,往往被避免使用。在实践中,包括 Python 自己的测试代码在内的许多地方都选择其他方法。
  • 拼接的单行字符串字面量更冗长,更难维护。
  • textwrap.dedent()是用 Python 实现的,因此需要一些运行时开销。它不能在性能关键的热路径中使用。

本 PEP 旨在为消除缩进的多行字符串提供一种内置语法,它既易于读写,在运行时也高效。

原理

此想法的主要替代方案是用 C 语言实现textwrap.dedent()并将其作为str.dedent()方法提供。
这种方法可以减少textwrap.dedent()的运行时开销。通过使其成为内置方法,当直接在字符串字面量上调用时,还允许进行编译时缩进移除。
然而,这种方法有几个缺点:

  • 为了支持用户希望在字符串中包含某些缩进的情况,dedent()方法需要接受一个参数来指定要移除的缩进量。这对用户来说将是繁琐且容易出错的。
  • 当使用续行符(行尾带有反斜杠的行)时,它们无法被消除缩进。
  • f-字符串可能会将表达式插值为多行字符串而没有缩进。在这种情况下,f-string +str.dedent()无法消除整个字符串的缩进。
  • t-字符串不创建 str 对象,因此它们不能使用str.dedent()方法。虽然可以向string.templatelib.Template添加dedent()方法,但这会导致不一致,因为 t-字符串和 f-字符串非常相似,但在消除缩进方面会有不同的行为。

str.dedent()方法对于非字面量字符串仍然有用,因此本 PEP 并不排斥这个想法。
然而,为了便于在多行字符串字面量中使用,提供专用的语法更为优越。

规范

为消除缩进的多行字符串添加一个新的字符串字面量前缀“d”。
该前缀可以与“f”、“t”和“r”前缀组合使用。
该前缀仅用于多行字符串字面量。
因此,它只能与三引号("""''')一起使用。
在单引号或双引号("')上使用它是一个语法错误。
开头的三引号后必须跟一个换行符。此换行符不包含在结果字符串中。
要移除的缩进量由紧接在末尾三引号之前的空白字符(空格' '或制表符'\t')决定。
在缩进中混合使用空格和制表符会引发TabError,类似于 Python 自己的缩进规则。
消除缩进的过程从字符串中的每一行移除确定的先导空白字符量。
比确定的缩进量短的行会变成一个空行(例如"\n")。
否则,如果该行不是以确定的缩进开始,Python 会引发IndentationError
除非与“r”前缀结合使用,反斜杠转义在处理完移除缩进后才被处理。
因此,你不能使用\t来创建缩进。
并且你可以使用行延续符(行尾的反斜杠)并从延续行中移除缩进。

示例:
(为清晰起见,空格显示为_,制表符显示为--->。错误消息仅为解释,实际消息可能不同。)

s=d""# SyntaxError: d-string must be a multiline strings=d"""Hello"""# SyntaxError: d-string must be a multiline strings=d"""Hello __World! """# SyntaxError: d-string must start with a newlines=d""" __Hello __World!"""# SyntaxError: d-string must end with an indent-only lines=d""" __Hello __World! """# 不移除缩进,因为末尾引号没有缩进。print(repr(s))# '__Hello\n__World!\n's=d""" __Hello __World! _"""# 移除一个空格的缩进。print(repr(s))# '_Hello\n_World!\n's=d""" __Hello __World! __"""# 移除两个空格的缩进。print(repr(s))# 'Hello\nWorld!\n's=d""" __Hello __World! ___"""# IndentationError: missing valid indentations=d""" >--->__Hello >__World! >"""# 允许制表符作为缩进。# 空格只是字符串的一部分,不是要移除的缩进。print(repr(s))# '__Hello\n__World!\n's=d""" >____World! --->__"""# TabError: mixing spaces and tabs in indentations=d""" __Hello \ __World!\ __"""# 行延续符正常工作print(repr(s))# 'Hello_World!'s=d"""\ __Hello __World __"""# SyntaxError: d-string must starts with a newline.s=dr""" __Hello\ __World!\ __"""# d-string 可以与 r-string 结合。print(repr(s))# 'Hello\\\nWorld!\\\n's=df""" ____Hello,{"world".title()}! ____"""# d-string 也可以与 f-string 和 t-string 结合。print(repr(s))# 'Hello, World!\n's=dt""" ____Hello, {"world".title()}! ____"""print(type(s))# <class 'string.templatelib.Template'>print(s.strings)# ('Hello, ', '!\n')print(s.values)# ('World',)print(s.interpolations)# (Interpolation('World', '"world".title()', None, ''),)

如何教授此功能

在教程中,可以结合三引号字符串字面量来介绍 d-string。
此外,可以在textwrap.dedent()的文档中添加一个注释,提供指向语言参考中 d-string 部分或教程相关部分的链接。

其他具有类似功能的语言

  • Java 15引入了一个称为文本块(text blocks)的功能。由于 Java 以前没有使用三引号,他们引入了用于多行字符串字面量的三引号,并自动移除缩进。
  • C# 11也引入了一个类似的功能,称为原始字符串字面量(raw string literals)。
  • JuliaSwift也支持自动移除缩进的三引号字符串字面量。
  • PHP 7.3引入了灵活的 Heredoc 和 Nowdoc 语法。虽然它使用结束标记(例如<<<END ... END)而不是三引号,但它也会从文本中移除缩进。

Java 和 Julia 使用缩进最少的那一行来确定要移除的缩进量。
Swift、C# 和 PHP 使用末尾三引号或结束标记的缩进。
本 PEP 选择了 Swift 和 C# 的方法,因为它更简单且更容易解释。

参考实现

PEP 822 的一个 CPython 实现可在methane/cpython#108获取。

被拒绝的想法

str.dedent()方法

正如原理部分提到的,本 PEP 并不拒绝str.dedent()方法这个想法。
一个用 C 实现的更快的textwrap.dedent()版本对运行时缩进移除会很有用。
然而,d-string 更适合多行字符串字面量,因为:

  • 它能很好地与 f/t-strings 配合工作。
  • 它允许更轻松地指定要移除的缩进量。
  • 它可以消除续行符的缩进。

三重反引号(Triple-backtick)

考虑使用三重反引号作为消除缩进的多行字符串的替代语法。
这种符号在 Markdown 中为我们所熟悉。虽然过去存在对某些键盘布局的担忧,但如今许多人已经习惯输入这种符号。
然而,当在 Markdown 中嵌入 Python 代码或反之亦然时,这种符号会产生冲突。
因此,考虑到这些缺点,增加引号字符的种类被认为不如为字符串字面量添加前缀优越。

__future__导入

除了为字符串字面量添加前缀之外,还考虑过使用__future__导入来改变多行字符串字面量的默认行为。
这可能有助于将来简化 Python 的语法。
但是,将所有现有的复杂代码库重写为新符号可能并不简单。
在该源代码中的所有多行字符串都被重写为新符号之前,无法利用自动缩进移除功能。
在所有用户能够将现有代码库重写为新符号之前,两种类型的 Python 语法将无限期共存。
因此,许多人更喜欢新的字符串前缀,而不是__future__导入。

版权

本文档置于公共领域或 CC0-1.0-Universal 许可证下,以更宽松者为准。

来源:https://github.com/python/peps/blob/main/peps/pep-0822.rst
最后修改时间:2026-01-07 15:13:47 GMT
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)或者 我的个人博客 https://blog.qife122.com/
对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)

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

零基础高效完成黑苹果安装:OpenCore Simplify自动化配置指南

零基础高效完成黑苹果安装&#xff1a;OpenCore Simplify自动化配置指南 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify OpenCore Simplify是一款专为…

作者头像 李华
网站建设 2026/6/22 11:03:43

Ghost Downloader:重新定义跨平台下载体验的智能工具

Ghost Downloader&#xff1a;重新定义跨平台下载体验的智能工具 【免费下载链接】Ghost-Downloader-3 A multi-threading async downloader with QThread based on PyQt/PySide. 跨平台 多线程下载器 协程下载器 项目地址: https://gitcode.com/GitHub_Trending/gh/Ghost-Do…

作者头像 李华
网站建设 2026/6/25 23:58:06

如何打造沉浸式活动互动体验?log-lottery带来的活动创新方案

如何打造沉浸式活动互动体验&#xff1f;log-lottery带来的活动创新方案 【免费下载链接】log-lottery &#x1f388;&#x1f388;&#x1f388;&#x1f388;年会抽奖程序&#xff0c;threejsvue3 3D球体动态抽奖应用。 项目地址: https://gitcode.com/gh_mirrors/lo/log-l…

作者头像 李华
网站建设 2026/7/2 1:24:09

黑苹果配置自动化工具:OpCore Simplify让复杂EFI生成变得简单

黑苹果配置自动化工具&#xff1a;OpCore Simplify让复杂EFI生成变得简单 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 你是否曾面对满屏的OpenCore…

作者头像 李华
网站建设 2026/7/1 15:49:31

收藏!Java开发者零门槛转型大模型指南:借技术积淀实现快速超车

在大模型技术重塑各行业核心生态的当下&#xff0c;“转型AI”已成为Java开发者职业进阶的必答题。但多数开发者深陷“入门无头绪”“不知如何结合现有业务落地”的困境&#xff0c;更有不少人发出灵魂拷问&#xff1a;“深耕Java多年&#xff0c;现在切入大模型领域是不是太晚…

作者头像 李华