网易首页 > 网易号 > 正文 申请入驻

Python 3.12 抢先看:更强大的 f-string!

0
分享至

△点击上方“Python猫”关注 ,回复“1”领取电子书

花下猫语:在 Python 潮流周刊的,我曾分享过一篇文章,这里再分享一篇译文。当时的推荐语是:

在 Python 3.12 之前,f-string 有什么限制?即将发布的 3.12 版本会带来哪些变化呢?新功能前瞻:嵌入表达式可以重用引号、f-string 中允许使用反斜杠、多行表达式中可写注释、任意级别的 f-string 嵌套、优化了 f-string 的错误提示……

来源:咸鱼运维杂谈

英文:https://realpython.com/python312-f-strings/

f-string 在 Python 3.12 前的限制

我们可以使用 Python 的 f-string 进行字符串格式化和插值,f-string 是以字母 F (大写小写都行)为前缀的字符串文本,这种文本允许插入变量和表达式,Python 会对其进行评估以生成最终字符串。

自从在 Python 3.6 版本中引入以来,f-string 在 Python 社区内已经广泛流行起来。人们对它们的采纳热情高涨,并将其作为现代 Python 编程的标准。

这其中的原因是什么呢?

这是因为 f-string 提供了一种简洁而易读的语法,允许我们格式化字符串并插入变量和表达式,而无需使用传统的.format()方法或旧式的字符串格式运算符(%)。

然而,为了引入 f-string,CPython 核心开发团队必须做出关键的决策,特别是在解析 f 字符串时,所以 f-string 有自己的解析代码。

换句话说,CPython 有一个专用的 f-string 解析器。因此,f-string 语法不是官方 Python 语法的一部分。

从核心开发人员的角度来看,这样的实现决策意味着相当大的维护成本,因为他们必须手动维护一个单独的解析器。

而且不作为官方语法的一部分,也意味着其他 Python 实现,如 PyPy,无法确定他们是否正确实现了 f-string。

然而,最重要的负担在于用户方面。从用户的角度来看,当前的 f-string 实现施加了一些限制:

  1. 无法重复使用引号或字符串分隔符

  2. 无法嵌入反斜杠,这意味着不能使用转义字符

  3. 禁止添加内联注释

  4. f-string 的嵌套仅限于 Python 中可用的引用变体

PEP 536 列出了这些限制。接下来我们通过一些小示例来了解这些限制如何影响我们在 Python 中使用 f-string

示例中使用的是 python 3.11 版本,如果使用较低的版本可能会导致输出不一样

我们首先在 f-string 中插入字典的 key

>>> employee = {
... "name": "John Doe",
... "age": 35,
... "job": "Python Developer",

>>> f"Employee: {employee["name"]}"
File "", line 1
f"Employee: {employee["name"]}"
^^^^
SyntaxError: f-string: unmatched '['

在上面的示例中,我们尝试在 f-string 中插入员工姓名,但是报错了。

因为"name"键周围的双引号会破坏字符串文本(f-string 无法重复使用引号或字符串分隔符)。

若要解决此问题,需要使用不同类型的引号来分隔键。

我们将双引号用于 f-string ,单引号用于字典 key,这下就不会报错了。

>>> f"Employee: {employee['name']}"
'Employee: John Doe'

f-string 的第二个限制是不能在嵌入式表达式中使用反斜杠字符

>>> words = ["Hello", "World!", "I", "am", "a", "Pythonista!"]

>>> f"{'\n'.join(words)}"
File "", line 1
f"{'\n'.join(words)}"
^
SyntaxError: f-string expression part cannot include a backslash

我们看到上面的示例得到了一个SyntaxError,因为 f-string 不允许在由大括号分隔的表达式中使用反斜杠字符。

我们可以通过下面的方法来实现,但并不优美。

>>> word_lines = "\n".join(words)

>>> f"{word_lines}"
'Hello\nWorld!\nI\nam\na\nPythonista!'

>>> print(f"{word_lines}")
Hello
World!
I
am
a
Pythonista!

f-string 的另一个限制是它们不允许在嵌入式表达式中插入注释

虽然这种限制可能看起来是多余的,但在某些情况下,一个好的注释可以帮助其他开发人员更好地理解你的代码。

>>> employee = {
... "name": "John Doe",
... "age": 35,
... "job": "Python Developer",

>>> f"""Storing employee's data: {
... employee['name'].upper() # Always uppercase name before storing
... }"""
File "", line 3
}"""
^
SyntaxError: f-string expression part cannot include '#'

在上面的示例中,我们使用了三引号生成多行的字符串,当我们尝试增加注释时,程序却报错了。

最后,f-string 还有另一个限制——f-string中的嵌套级别数受 Python 中可用的字符串分隔符的限制,这些分隔符是"'"""'''

>>> f"""{
... f'''{
... f"{f'{42}'}"

'42'

>>> f"""{
... f'''{
... f"{f'{f"{42}"}'}"
... }'''
... }"""
File "", line 1
(f"{f'{f"{42}"}'}")
^
SyntaxError: f-string: f-string: unterminated string

尽管嵌套 f-string 可能没有很多用例,但如果我们在特定用例中需要额外的嵌套级别,那么就不走运了,因为不能重用引号。

需要注意的是:只有三引号的 f-string 可以跨越多行,但是这个是 python 字符串的特征。

虽然 f-string 字符串非常酷,大多数 Python 开发人员都喜欢它们,但上面这些限制让 f-string 感觉不完整,并且与 Python 本身的一般行为不一致。

幸运的是,Python 在不断改进,下一个版本 3.12 正在解除这些限制使 f-string 变得更好。

Python 3.12 中 f-string 的改动

  • 可重复使用引号,不再严格区分双引号单引号

在新的 f-string 实现中,嵌入的表达式组件可以包含任何 Python 表达式,包括使用与包含的 f-string 相同类型的引号的字符串文本。

>>> employee = {
... "name": "John Doe",
... "age": 35,
... "job": "Python Developer",

>>> f"Employee: {employee["name"]}"
'Employee: John Doe'

在上面的示例中,我们使用了双引号来定义 f-string 并分隔employee字典键。

现在,在嵌入式表达式中使用字符串文本时,不必切换到其他类型的引号。

尽管这种新行为看起来很酷且一致,但有些人认为在同一 f-string 中重用引号令人困惑且难以阅读。

这些人可能是对的——重用引号违反了 Python 规则,即匹配的引号对分隔字符串。

但是,专注于将纯字符串部分与嵌入的表达式部分分开有助于提高可读性。

在这方面,PEP 701 的作者说: We believe that forbidding quote reuse should be done in linters and code style tools and not in the parser, the same way other confusing or hard-to-read constructs in the language are handled today 我们认为,禁止引用重用应该在 linters 和代码样式工具中完成,而不是在解析器中,就像今天处理语言中其他令人困惑或难以阅读的结构一样

这种说法是有道理的。但是最佳做法和样式建议可能依旧是在代码中避免使用它们。

因此,如果发现重用引号不可读或令人困惑,那就坚持在 f-string 中使用不同引号的旧做法。

  • 允许使用反斜杠

f-string 不支持反斜杠是 Python 3.11 及更低版本中的另一个问题,在 Python 3.12 中,此问题已解决。

>>> words = ["Hello", "World!", "I", "am", "a", "Pythonista!"]

>>> f"{'\n'.join(words)}"
'Hello\nWorld!\nI\nam\na\nPythonista!'

>>> print(f"{'\n'.join(words)}")
Hello
World!
I
am
a
Pythonista!

能够在嵌入在 f-string 中的表达式中包含反斜杠是一个很好的进步,它省去了我们寻找替代解决方法的工作量。

  • 支持多行实现和注释

f-string 还允许在这些表达式中使用多行表达式和内联注释。

>>> f"""Storing employee's data: {
... employee['name'].upper() # Always uppercase name before storing
"Storing employee's data: JOHN DOE"

在 Python 3.12 的 f-string 中,我们可以定义跨越多个物理行的表达式。如果需要,每行都可以包含内联注释。

  • 实现任意级别的 f-string 嵌套

由于允许引号重用,新的 f-string 允许任意级别的嵌套。

此功能的实用性有限,因为许多级别的嵌套可能会使代码难以阅读和理解。

>>> f"{
... f"{
... f"{
... f"{
... f"{
... f"Deeply nested f-string!"


'Deeply nested f-string!'

在上面的示例中,我们注意到新的 f-string 允许在表达式中的大括号内使用换行符,这个跟常规 python 规范一致(常规 python 允许我们将表达式括在一对括号中,使其能够跨越多行)。

  • 更具体更清晰的报错信息

Python 3.12 的新 f-string 消除了如何在现实代码中使用 f-string 的几个限制并且将其变成了新功能。

但远不止于此。

以前,这些增强的错误消息不适用于 f-string,因为它们不使用 PEG 解析器。

因此,在 Python 3.12 之前,与 f-string 相关的错误消息不太具体和清晰。

Python 开发团队在引入 PEG 解析器后投入了大量工作来改进 Python 错误消息,现在使用 PEG 解析器来解析新的 f-string 语法,所以你会得到一个额外的、显着的好处——更具体更清晰的报错信息。

例如,比较以下 f-string 在 3.11 与 3.12 中生成的错误消息。

>>> # Python 3.11
>>> f"{42 + }"
File "", line 1
(42 + )
SyntaxError: f-string: invalid syntax

>>> # Python 3.12
>>> f"{42 + }"
File "", line 1
f"{42 + }"
^
SyntaxError: f-string: expecting '=', or '!', or ':', or '}'

第一个示例中的错误消息是通用的,不指向违规行中错误的确切位置。此外,表达式在括号中,这会增加问题的噪音,因为原始代码不包含括号。

在 Python 3.12 中,错误消息更加精确。它指示问题在受影响管中的确切位置。此外,异常消息提供了一些可能有助于我们解决问题的建议。

Python 3.12 的 f-string 仍有不足

新的 f-string 不会消除 f-string 的一些当前限制。

例如,有关使用冒号 (:)、感叹号 (!) 和转义带反斜杠的大括号的规则仍然存在。

要将冒号和感叹号 (:!) 用于字符串格式以外的目的,我们需要用一对括号将包含这些符号之一的表达式括起来。否则,f-string 将不起作用。

根据PEP 701的作者的说法,这就是他们没有取消限制的原因: The reason is that this [removing the restriction] will introduce a considerable amount of complexity [in the f-string parsing code] for no real benefit. 原因是这[删除限制]将[在f字符串解析代码中]引入相当大的复杂性,而没有真正的好处

除了将这些字符用于字符串格式化之外,我们几乎找不到适合它们的用例。即使是 PEP 701 中的相关示例也毫无用处。

>>> # Python 3.11
>>> f"Useless use of lambdas: { lambda x: x*2 }"
File "", line 1
( lambda x)
SyntaxError: f-string: invalid syntax

>>> # Python 3.12
>>> f"Useless use of lambdas: { lambda x: x*2 }"
File "", line 1
f'Useless use of lambdas: { lambda x: x*2 }'
^^^^^^^^^
SyntaxError: f-string: lambda expressions are not allowed without parentheses

在上面的示例中,我们使用冒号作为匿名函数的一部分,但是却报错了。

如果要避免这个错误,我们必须用括号括起来。

>> f"Useless use of lambdas: { (lambda x: x*2) }"
'Useless use of lambdas: at 0x1010747c0>'

最后,新的 f-string 允许我们使用反斜杠转义字符,但不允许使用反斜杠转义大括号

>>> f"\{ 42 \}"
File "", line 1
f"\{ 42 \}"
SyntaxError: unexpected character after line continuation character

在此示例中,我们尝试使用反斜杠来转义大括号。但是,代码不起作用。

以下是 PEP 701 的作者对此限制的看法: We have decided to disallow (for the time being) using escaped braces (\{ and \}) in addition to the {{ and }} syntax. Although the authors of the PEP believe that allowing escaped braces is a good idea, we have decided to not include it in this PEP, as it is not strictly necessary for the formalization of f-strings proposed here, and it can be added independently in a regular CPython issue 我们决定(暂时)禁止使用转义大括号( \{ 和 \} )以及 {{ 和 }} 语法。尽管 PEP 的作者认为允许转义大括号是个好主意,但我们决定不将其包含在此 PEP 中,因为它对于此处提出的 f-string 的形式化并不是绝对必要的,并且可以在常规的 CPython 问题中独立添加

如果要转义 f-string 中的大括号,需要在外面多加一层大括号。

>>> f"{{ 42 }}"
'{ 42 }'

将大括号加倍是目前版本在 f-string 中转义这些字符的方法,但是将来可能会改变。

Python猫技术交流群开放啦!群里既有国内一二线大厂在职员工,也有国内外高校在读学生,既有十多年码龄的编程老鸟,也有中小学刚刚入门的新人,学习氛围良好!想入群的同学,请在公号内回复『交流群』,获取猫哥的微信 (谢绝广告党,非诚勿扰!)~

还不过瘾?试试它们

如果你觉得本文有帮助

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
晋级18强赛后伊万做出意外决定,获宋凯批准,中方教练组看懂了

晋级18强赛后伊万做出意外决定,获宋凯批准,中方教练组看懂了

徽派体育
2024-06-13 10:35:42
“拯救”国足的新加坡门将:家中摊位售卖食品被中国人买空

“拯救”国足的新加坡门将:家中摊位售卖食品被中国人买空

封面新闻
2024-06-12 16:57:06
美国的衰落,比你想象中要快!

美国的衰落,比你想象中要快!

讲者普拉斯
2024-06-08 10:56:29
阿曼达·霍尔顿脱掉胸罩和内裤穿着透明连衣裙宣传 Netflix 的新节目

阿曼达·霍尔顿脱掉胸罩和内裤穿着透明连衣裙宣传 Netflix 的新节目

综艺拼盘汇
2024-06-13 09:08:16
法媒:马克龙会否重蹈戴高乐覆辙?

法媒:马克龙会否重蹈戴高乐覆辙?

参考消息
2024-06-12 14:04:09
金英权:在场下看韩国比赛和上场踢感觉不一样,看球我也很紧张

金英权:在场下看韩国比赛和上场踢感觉不一样,看球我也很紧张

懂球帝
2024-06-13 10:52:09
罕见省部级高干在中央党报公开表达“不满”:困惑很久,不吐不快

罕见省部级高干在中央党报公开表达“不满”:困惑很久,不吐不快

华人星光
2024-06-07 19:20:09
昨晚,“NBA”死了

昨晚,“NBA”死了

左右为篮
2024-06-13 13:07:09
FMVP大热门!杰伦总决赛3场场均24分6板6助 断帽3.3次&命中率55%

FMVP大热门!杰伦总决赛3场场均24分6板6助 断帽3.3次&命中率55%

直播吧
2024-06-13 11:26:05
曾经的两个好朋友,已成两敌人,再想买先进装备是没地方可买了

曾经的两个好朋友,已成两敌人,再想买先进装备是没地方可买了

历史与财经
2024-06-12 12:52:02
重磅!中国忍无可忍,已准备出手!

重磅!中国忍无可忍,已准备出手!

华人星光
2024-06-12 15:51:14
河南最美女警花被局长霸占,丈夫一招反击,亲手把局长送进监狱!

河南最美女警花被局长霸占,丈夫一招反击,亲手把局长送进监狱!

古今档案
2023-12-24 22:37:30
忘掉过去:除卡塔尔外,国足亚洲杯同组对手皆未晋级18强赛

忘掉过去:除卡塔尔外,国足亚洲杯同组对手皆未晋级18强赛

鲁中晨报
2024-06-12 14:35:04
徐杰代表广州出战体院杯!发挥炸裂,降维打击,球迷:砍瓜切菜

徐杰代表广州出战体院杯!发挥炸裂,降维打击,球迷:砍瓜切菜

小豆豆赛事
2024-06-13 09:55:34
周恩来宣布任命决定,傅作义当场大哭并振臂高呼,会议中途暂停

周恩来宣布任命决定,傅作义当场大哭并振臂高呼,会议中途暂停

历史实战派
2024-06-12 11:23:41
刚刚!国家敲定重要决定,2756家银行网点关停,释放了什么信号

刚刚!国家敲定重要决定,2756家银行网点关停,释放了什么信号

小马哥谈体育
2024-06-12 21:41:23
广州地铁允许个人投放后,成了大型整活现场,被网友笑麻了

广州地铁允许个人投放后,成了大型整活现场,被网友笑麻了

新动察
2024-06-13 09:35:53
又赚到了!孟加拉四处炫耀中国给建的大桥:开通当天过路费破千万

又赚到了!孟加拉四处炫耀中国给建的大桥:开通当天过路费破千万

文雅笔墨
2024-06-12 21:49:22
闯祸!留学生用无人机拍摄航母制造厂,被以二战法律指控6项罪名

闯祸!留学生用无人机拍摄航母制造厂,被以二战法律指控6项罪名

小刀99
2024-06-12 16:33:27
寻找东莞散布在世界各地的历史记忆,为市博物馆新馆累积藏品

寻找东莞散布在世界各地的历史记忆,为市博物馆新馆累积藏品

南方都市报
2024-06-08 18:08:16
2024-06-13 13:22:44
Python猫
Python猫
人生苦短,我用Python。博客:https://pythoncat.top
633文章数 8097关注度
往期回顾 全部

科技要闻

"在小红书,员工是实验品,不好用就扔掉"

头条要闻

女子退租时遭房东"摇人组团定损" 警方介入退还押金

头条要闻

女子退租时遭房东"摇人组团定损" 警方介入退还押金

体育要闻

国足,别辜负这场奇迹!

娱乐要闻

森林北报案,称和汪峰的感情遭受压力

财经要闻

徽商银行的影子 借基金向地方城投放贷?

汽车要闻

升级8155芯片 新款卡罗拉锐放将于今日上市

态度原创

家居
游戏
旅游
手机
公开课

家居要闻

原木绿居 阳光编织的自然生活诗篇

《波斯王子:时之砂 重制版》战斗与关卡将重新设计 法拉戏份增加

旅游要闻

山西文旅厅厅长与董宇辉拉家常:中午回家吃了饭

手机要闻

OPPO Find X7 / 一加12等手机将于 ColorOS15 公测实况照片功能

公开课

近视只是视力差?小心并发症

无障碍浏览 进入关怀版