page contents

Python 3.12 f-string 这个改进救了多少新手?

比如你顺手写了个 f"{"hello"}",满心期待它输出 hello,结果 Python 告诉你语法错误。你只好改成 f"{'hello'}",单双引号交替着用。要是再往里嵌套一层呢?你得一层单一层双,像叠衣服一样,三层以上就很难看了,还得数清楚哪层用哪种引号。

attachments-2026-07-HTkQy1Ut6a4c59d5bffe5.png

你有没有遇到过这种情况——写个 f-string,里头想套一层引号,Python 直接给你一个 SyntaxError?

比如你顺手写了个 f"{"hello"}",满心期待它输出 hello,结果 Python 告诉你语法错误。你只好改成 f"{'hello'}",单双引号交替着用。要是再往里嵌套一层呢?你得一层单一层双,像叠衣服一样,三层以上就很难看了,还得数清楚哪层用哪种引号。

反斜杠也一样离谱。想在 f-string 表达式里写个 \n 换行符,Python 直接报错,逼你先赋值给变量再塞进去。多行 f-string 里想写个注释?不好意思,不支持。

f-string 是 Python 3.6 引入的字符串格式化语法,因为简洁好用,几乎所有 Python 程序员每天都在用。但它从一开始就有几个让人头疼的限制,这些限制不是 bug,而是设计时为了简化解析器做的取舍。问题是,这些取舍让新手的日常编码变得很不舒服。

好消息是:Python 3.12 终于把这些限制全部解除了。PEP 701 重新定义了 f-string 的语法规则,引号可以复用、反斜杠可以写、注释可以加、嵌套深度不再有限制。今天咱们一个一个掰开讲,看完你就再也不用为这些事发愁了。

引号终于能复用了

先说最痛的那个点——引号。这个坑几乎每个用 f-string 的新手都踩过,而且踩了之后往往一脸懵,不知道为什么明明看起来合法的代码却报错。

在 Python 3.12 之前,f-string 表达式里的引号不能和外面的引号用同一种。你写双引号的 f-string,里头就必须用单引号:

# 3.12 之前:双引号f-string里只能用单引号

name = "Tom"

msg = f"Hello, {name}"  # OK,里头没引号

 

# 但这样不行:

f"{"hello"}"  # SyntaxError! 外面双引号里头也是双引号

# 只能这样绕:

f"{'hello'}"  # 改成单引号才行

一层还好,两层就开始难受了:

# 嵌套两层:一层单一层双交替

f"{'{"key": "value"}'}"  # 像密码一样难读

三层以上基本就写不了了——你手里的引号只有两种(单和双),三种嵌套就用完了。更离谱的是,有些新手为了绕这个限制,甚至在 f-string 里用三引号来做嵌套,代码变得又丑又难维护。

Python 3.12 之后,同一个 f-string 里可以复用同一种引号了:

# 3.12 之后:引号可以复用!

f"{"hello"}"  # OK!外面双里头也双

f"{"{"nested"}"}"  # 两层双引号也OK

原理很简单:PEP 701 把 f-string 的内部表达式和外部字符串定义为独立的字符串区域,它们之间互不干扰。就像两个房间各自关门,隔壁用什么引号我不管。这个改动不光解决了嵌套问题,还让整个 f-string 的语法变得和普通 Python 表达式一样自然——你在表达式里用什么引号,完全由你自己决定。

实际场景:写配置模板或者 JSON 格式化的时候,键值都用双引号,以前你得在 f-string 里切换成单引号,现在直接双引号通吃了:

import json

config = {"host": "localhost", "port": 8080}

 

# 以前必须这样写(切换成单引号)

msg = f'Config: {json.dumps(config)}'

# 现在双引号一路到底

msg = f"Config: {json.dumps(config)}"

再举个例子,写 HTML 标签的时候属性值都用双引号,以前在 f-string 里也得绕:

# 以前:HTML属性双引号和f-string冲突

html = f'<div class="{cls}">{content}</div>'

# 现在:所有双引号统一

html = f"<div class="{cls}">{content}</div>"

别小看这个变化,引号统一之后代码一眼就能看懂,不用再数哪层用哪种引号了。

反斜杠不再被禁了

第二个痛点:反斜杠。这个限制比引号还让人恼火,因为它逼你做一件完全没必要的事——多写一行代码。

在 Python 3.12 之前,f-string 表达式里不能写反斜杠。你想把换行符替换成空格:

# 3.12 之前:报错

f"{text.replace(' ', ' ')}"

# SyntaxError: f-string expression part cannot include a backslash

Python 直接告诉你:表达式里不允许反斜杠。理由是 f-string 在解析阶段就把表达式里的内容当成字符串处理了,而反斜杠在字符串里有特殊含义,解析器搞不清楚它到底是给 f-string 的还是给表达式的。

你只能先赋值给一个变量:

# 绕法:先赋值

newline = " "

f"{text.replace(newline, ' ')}"

明明一行就能搞定的事,非要拆成两行。这种"为了绕限制而多写代码"的感觉,谁踩过都知道多烦。更烦的是,你还得给这个临时变量起个名字,叫 newline 吗?叫 NL 吗?叫 sep 吗?每次都要想一下,最后代码里堆了一堆这种一次性的变量名。

Python 3.12 之后,反斜杠可以直接写在表达式里了:

# 3.12 之后:反斜杠直接写

f"{text.replace(' ', ' ')}"  # OK!

处理文本的时候特别方便。把换行符换成空格、把制表符换成逗号、把路径里的反斜杠换成正斜杠,全都能一行搞定:

# 换行变空格

f"{text.replace(' ', ' ')}"

 

# 制表符变逗号

f"{text.replace(' ', ',')}"

 

# Windows路径变正斜杠

f"{path.replace('\\', '/')}"

还有一个很常见的场景:你想在 f-string 里用 repr() 查看变量的原始值,以前 repr() 输出的引号可能跟 f-string 的引号冲突,现在引号可以复用了,repr() 也更方便用了:

# 引号复用后repr随便用

f"Value: {repr(data)}"  # OK!

以前每个都要先定义变量,现在直接写就行。代码少了,脑子也轻松了。

多行 f-string 能写注释了

第三个痛点:多行 f-string 里不能写注释。这个限制对写复杂模板的人来说最难受。

你写了个多行模板,想在里头标注每个变量是什么:

# 3.12 之前:注释会直接输出

msg = f"""

    Hello {name},

    # 这行不是注释,会原样输出!

    Welcome to {city}!

"""

那行 # 注释不会被 Python 当成注释处理,而是直接出现在输出文本里。你说"我是注释",Python 说"我不听,直接打印"。对于生成邮件模板、报告模板这种场景,注释污染输出是个很现实的问题——你的注释直接出现在给用户看的文本里了。

Python 3.12 之后,注释可以写在 {} 表达式内部了:

# 3.12 之后:注释写在表达式内部

msg = f"""

    Hello {

        name  # 用户的名字

    },

    Welcome to {

        city  # 所在城市

    }!

"""

注释写在 {} 内部,不会出现在输出里。这对复杂的多行模板特别有用,过几个月再看这段代码,一眼就知道每个位置填的是什么。

你还能在表达式内部换行写更复杂的逻辑:

# 表达式内部可以写复杂逻辑

msg = f"Score: {

    'pass' if score >= 60 else 'fail'  # 判断是否及格

}"

再举个更实用的例子,生成邮件模板的时候,你可以在每个变量旁边标注它的来源:

# 邮件模板:每个变量都标注来源

email = f"""

Dear {

    customer['name']  # 从客户信息表取名字

},

 

Your order #{

    order['id']  # 订单编号

} has been shipped.

Estimated delivery: {

    delivery_date  # 预计送达日期

}.

"""

以前这种写法要么报错要么得拆出去,现在直接写就行。再也不怕过几个月回来看不懂了。

嵌套终于没有限制了

最后一个痛点:嵌套深度限制。

以前 f-string 的嵌套深度受引号限制,因为只有单引号和双引号两种可以交替使用。理论上一层单一层双交替着,最多嵌套两三层就到头了。想写一个四层嵌套的 f-string?对不起,你的引号不够用了。有些新手为了绕这个限制,甚至在 f-string 里混用三引号,代码既丑又难维护。

Python 3.12 解除了这个限制,因为引号可以复用了,嵌套深度自然就不受限了:

# 3.12 之后:嵌套不受限

result = f"{

    f"{

        f"{

            value

        }"

    }"

}"

虽然实际编程中很少需要嵌套这么深,但解除限制意味着你不用担心层级撞墙了。你自由组合 f-string 和其他表达式,想嵌套几层就嵌套几层。

一个更实用的场景是结合字典嵌套:

data = {"user": {"name": "Tom", "age": 25}}

 

# 嵌套取值,不用担心层级限制

msg = f"User {data['user']['name']} is {data['user']['age']}"

# 输出:User Tom is 25

以前多层字典取值在 f-string 里要格外小心引号,现在引号可以复用了,写起来就自然多了。

好,总结一下这4个改进:

1. 引号复用:同一个 f-string 里内外可以用同一种引号,嵌套不再需要交替切换

2. 反斜杠解禁:表达式里可以直接写 \n \t 等转义字符,不用先赋值给变量

3. 表达式内注释:{} 内部可以写 # 注释,不会出现在输出文本里

4. 嵌套不限深度:f-string 嵌套深度不再受引号种类限制,自由组合

PEP 701 的核心思路是:把 f-string 的表达式部分和字符串部分分开解析,让表达式内部可以像普通 Python 代码一样自由发挥。之前那些限制,本质上都是因为解析器把 f-string 当成"一个整体字符串"来处理,内外不分家。PEP 701 改了这个设计,内外各自独立,所以引号复用、反斜杠、注释这些之前被禁止的东西,自然就都放开了。

怎么确认你的 Python 版本?在终端里运行 python --version 就能看到。如果你已经用的是 3.12 或更高版本(比如 3.13、3.14、3.15),那这些改进你现在就能用。如果还在用 3.11 或更早版本,升级之后 f-string 的体验会完全不一样。

 更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

 

  • 发表于 2026-07-07 09:44
  • 阅读 ( 30 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

2251 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. Pack 2251 文章
  3. 小柒 2228 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章