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

Python 3.14 t-string 要来了,它与 f-string 有何不同?

0
分享至

△△请给“Python猫”加星标 ,以免错过文章推送


Python 最近出了个大新闻:PEP-750 t-string 语法被正式采纳了!

这意味着 Python 将在今年 10 月发布的 3.14 版本中引入一种新的字符串前缀 t,称为模板字符串(Template Strings),即 t-string。

这是继 f-string 之后,字符串处理能力的重大升级,旨在提供更安全、更灵活的字符串插值处理机制。

t-string 的基本语法与 f-string 非常相似,但得到的结果却大为不同:

name = "World" # f-string 语法 formatted = f"Hello {name}!" print(type(formatted))  # 输出: print(formatted)  # 输出:Hello World! # t-string 语法 templated = t"Hello {name}!" print(type(templated))  # 输出: print(templated.strings)  # 输出:('Hello ', '') print(templated.interpolations[0].value)  # 输出:World print("".join(         item if isinstance(item, str) else str(item.value)         for item in templated     ))  # 输出:Hello World!

如上所述,t-string 与 f-string 不同的是,它不会立即得到普通字符串,而是返回一个新的类型 Template(来自 Python 3.14 新增的标准库模块 string.templatelib)。

这个类型不能直接作为普通字符串输出,但它提供了对字符串和其内部插值表达式的结构化访问,使得开发者能够在字符串组合插入值前添加拦截和转换。

一句话总结 t-string 的核心特点就是延迟渲染。

为什么要设计 t-string?

f-string 因其简洁易用而广受欢迎,但它也存在一些无法忽视的局限性:

  1. 安全隐患 :当直接将用户输入嵌入到 SQL 查询、HTML 内容或系统命令中时,f-string 可能导致注入攻击

  2. 缺乏转换能力 :f-string 没有提供在字符串组合前拦截和转换插入值的机制

  3. 灵活性不足 :对于复杂的字符串处理任务,f-string 的能力有限

提升字符串处理的安全性

不谨慎使用 f-string,可能导致安全漏洞:

# 使用 f-string 的不安全示例(SQL 注入风险) sql_query = f"SELECT * FROM users WHERE name = '{user_input}'" # 使用 f-string 的不安全示例(XSS 风险) html_content = f" {user_input} "

而 t-string 允许开发者在字符串组合前对插值进行适当处理:

# 使用 t-string 的安全示例 evil = " " template = t" {evil}" # 可以定义处理函数来转义内容 assert html(template) == " "
增强字符串处理的灵活性

t-string 最大的优势在于它提供了统一的字符串处理机制,让开发者可以根据实际需求实现各种自定义渲染逻辑。这种设计避免了为每种场景创建专门语法的复杂性,同时保持了 Python 简洁统一的风格。

以下示例展示了如何基于同一个 t-string 模板,利用不同的渲染器输出不同的格式:

from string.templatelib import Template, Interpolation data = {"name": "Python猫", "age": 18} template = t"用户 {data['name']} 的年龄是 {data['age']}" def standard_renderer(template: Template) -> str:     """标准文本渲染"""     return"".join(         item if isinstance(item, str) else str(item.value)         for item in template     ) def json_renderer(template: Template) -> str:     """JSON格式渲染"""     import json, re     values = {}     for item in template:         ifnot isinstance(item, str):             # 使用正则表达式从表达式中提取键名             # 匹配 data['name'] 或 data["name"] 模式中的name             match = re.search(r"\['([^']+)'\]|\[\"([^\"]+)\"\]", item.expression)             if match:                 # 获取匹配的第一个分组                 key = match.group(1) if match.group(1) else match.group(2)                 values[key] = item.value     return json.dumps(values, ensure_ascii=False)      def xml_renderer(template: Template) -> str:     """XML格式渲染"""     parts = [""]     for item in template:         ifnot isinstance(item, str) and hasattr(item, "expression"):             name = item.expression.split("'")[1] if"'"in item.expression else item.expression             parts.append(f"  <{name}>{item.value} {name}>")     parts.append("")     return"\n".join(parts) # 同一个模板,不同的输出格式 print(standard_renderer(template))  # 输出: 用户 Python猫 的年龄是 18 print(json_renderer(template))      # 输出: {"name": "Python猫", "age": 18} print(xml_renderer(template))       # 输出: \n   Python猫 \n   18 \n

这种灵活性是 f-string 所不具备的,对于构建各种 DSL(领域特定语言)、模板引擎或格式化系统非常有价值。

Template 类的结构

t-string 求值后的 Template 类具有以下主要属性和方法:

class Template:     strings: tuple[str, ...]     """     模板中字符串部分的非空元组。     包含 N+1 个元素,其中 N 是模板中插值表达式的数量。     """     interpolations: tuple[Interpolation, ...]     """     模板中插值部分的元组。     如果没有插值表达式,这将是一个空元组。     """     def __new__(cls, *args: str | Interpolation):         """         创建一个新的 Template 实例。         参数可以按任意顺序提供。         """         ...     @property     def values(self) -> tuple[object, ...]:         """         返回模板中每个 Interpolation 的 `value` 属性组成的元组。         如果没有插值表达式,这将是一个空元组。         """         ...     def __iter__(self) -> Iterator[str | Interpolation]:         """         迭代模板中的字符串部分和插值表达式。         这些可能以任意顺序出现。不包含空字符串。         """         ...

这种结构使开发者能够:

  • 访问原始字符串片段(strings)

  • 访问插值表达式及其计算结果(interpolations)

  • 直接获取所有插值的值(values)

  • 按顺序迭代模板的所有组成部分

注:__iter__ 函数注释说出现顺序不固定,但 PEP 文档中它的具体实现却是按序的,我认为是注释有误。

t-string 与 f-string 的异同点 相似之处

  1. 基本语法 :二者都使用花括号 {} 作为插值表达式的分隔符

  2. 表达式求值 :都支持在花括号中放置任意 Python 表达式

  3. 格式说明符 :都支持格式说明符(如 .2f )和转换说明符(如 !r )

  4. 引号支持 :都支持所有有效的引号标记( ' 、 " 、 ''' 、 """ )

  5. 大小写不敏感前缀 : t 和 T 都是有效的,就像 f 和 F

不同之处
  1. 返回类型 :f-string 直接返回 str 类型,而 t-string 返回 Template 类型

  2. 求值时机 :f-string 在定义时立即求值,t-string 提供延迟求值能力

  3. 结构访问 :t-string 允许访问原始模板的结构(字符串部分和插值部分)

  4. 处理模型 :f-string 是"即时完成"模型,t-string 是"预处理+转换"模型

t-string 的应用场景 1. 安全的 HTML 模板

使用 t-string 可以创建出自动转义用户输入的 HTML 模板:

def html(template: Template) -> str:     parts = []     for item in template:         if isinstance(item, str):             parts.append(item)         else:  # Interpolation             parts.append(html_escape(item.value))     return "".join(parts) user_input = " " safe_html = html(t" {user_input} ") # 输出:
2. 安全的 SQL 查询构建

t-string 可以构建防注入的 SQL 查询:

def safe_sql(template: Template) -> str:     parts = []     params = []          for item in template:         if isinstance(item, str):             parts.append(item)         else:             parts.append("?")             params.append(item.value)          return"".join(parts), params user_id = "user' OR 1=1--" query, params = safe_sql(t"SELECT * FROM users WHERE id = {user_id}") # query: "SELECT * FROM users WHERE id = ?" # params: ["user' OR 1=1--"]
3. 结构化日志

使用 t-string 可以实现优雅的结构化日志记录:

import json import logging from string.templatelib import Template, Interpolation class TemplateMessage:     def __init__(self, template: Template) -> None:         self.template = template          @property     def message(self) -> str:         # 格式化为可读消息         return f(self.template)  # 使用自定义 f() 函数          @property     def values(self) -> dict:         # 提取结构化数据         return {             item.expression: item.value             for item in self.template.interpolations         }          def __str__(self) -> str:         returnf"{self.message} >>> {json.dumps(self.values)}" action, amount, item = "traded", 42, "shrubs" logging.info(TemplateMessage(t"User {action}: {amount:.2f} {item}")) # 输出: User traded: 42.00 shrubs >>> {"action": "traded", "amount": 42, "item": "shrubs"}
4. 安全的子进程调用

PEP-787 专门针对 t-string 在子进程调用中的场景作了扩展,使 subprocess 模块能原生支持 t-string:

# 不安全的 f-string 用法 subprocess.run(f"echo {message_from_user}", shell=True)  # 命令注入风险 # 安全的 t-string 用法 subprocess.run(t"echo {message_from_user}")  # 自动进行适当的命令转义

这种方式既保留了字符串命令的可读性,又避免了安全风险。

t-string 的进阶用法 1. 自定义多功能模板渲染器

t-string 的真正威力在于可以自定义渲染器模板:

from string.templatelib import Template, Interpolation import html def smart_renderer(template: Template, context="text") -> str:     """上下文感知的渲染器     根据context参数自动决定如何处理每个插值:     - "text": 普通文本模式,直接转为字符串     - "html": HTML模式,自动转义HTML特殊字符,防止XSS     - "sql": SQL模式,自动转义SQL特殊字符,防止注入     """     parts = []          for item in template:         if isinstance(item, str):             parts.append(item)         else:  # Interpolation             value = item.value             expression = item.expression                          # 基于值类型和上下文进行智能处理             if context == "html":                 # HTML模式:自动转义HTML特殊字符                 parts.append(html.escape(str(value)))             elif context == "sql":                 # SQL模式:防止SQL注入                 if isinstance(value, str):                     # 将1个单引号转义成2个                     escaped_value = value.replace("'", "''")                     parts.append(f"'{escaped_value}'")                 elif value isNone:                     parts.append("NULL")                 else:                     parts.append(str(value))             else:                 parts.append(str(value))          return"".join(parts) # 同一个模板在不同上下文中的自动适配渲染 user_input = " " template = t"用户输入: {user_input}" print(smart_renderer(template, context="html")) # 输出: 用户输入: # SQL注入防护示例 user_id = "1'; DROP TABLE users; --" sql_template = t"SELECT * FROM users WHERE id = {user_id}" print(smart_renderer(sql_template, context="sql")) # 输出: SELECT * FROM users WHERE id = '1''; DROP TABLE users; --' # f-string 对于SQL注入,必须先处理值,再放入f-string escaped_id = user_id.replace("'", "''") sql_safe_id = f"'{escaped_id}'" print(f"SQL查询(f-string): SELECT * FROM users WHERE id = {sql_safe_id}")
2. 结构化嵌套模板处理

t-string 和 f-string 在嵌套使用时有本质区别:

# f-string的嵌套:内部表达式立即求值,信息丢失 value = "world" inner_f = f"inner {value}" outer_f = f"outer {inner_f}" print(outer_f)  # 输出: outer inner world print(type(outer_f))  # - 只是普通字符串 # t-string的嵌套:保留完整结构信息 inner_t = t"inner {value}" outer_t = t"outer {inner_t}" print(type(outer_t))  # print(type(outer_t.interpolations[0].value))  # 也是Template对象! # 可以访问和处理任意深度的嵌套结构 user = {"name": "Alice", "age": 30} message = t"用户{user['name']}信息: {t'年龄:{user['age']}'}" inner_template = message.interpolations[1].value print(inner_template.strings)  # 输出: ('年龄:', '') print(inner_template.interpolations[0].value)  # 输出: 30

这种结构化处理能力使 t-string 特别适合构建复杂的模板系统,可以按需延迟或自定义渲染过程的所有部分。

3. 延迟求值与异步处理

t-string 的结构特性使得它支持延迟求值和异步处理。以下是异步模板渲染示例:

import asyncio # 模拟异步数据获取 asyncdef fetch_data(key: str) -> str:     await asyncio.sleep(0.1)  # 模拟网络延迟     returnf"获取的{key}数据" asyncdef render_async(template):     tasks = {}     # 并行启动所有异步查询     for item in template.interpolations:         tasks[item.expression] = asyncio.create_task(             fetch_data(item.expression)         )          # 等待所有查询完成     for expr, task in tasks.items():         tasks[expr] = await task          # 组装结果     result = []     for item in template:         if isinstance(item, str):             result.append(item)         else:             result.append(tasks[item.expression])          return"".join(result) asyncdef main():     template = t"用户: {user}, 年龄: {age}"     result = await render_async(template)     print(result)  # asyncio.run(main())

这种模式的关键优势:

  • 结构保留 : 可以获取完整表达式信息

  • 并行获取 : 同时处理多个异步任务

  • 延迟组合 : 等所有数据就绪再拼接

总结

Python 的 t-string 语法是对字符串处理能力的重要扩展,它在保持与 f-string 语法相似性的同时,提供了更灵活、更安全的字符串插值处理机制。通过将字符串模板结构化为 Template 对象,开发者可以在字符串组合前对插值进行拦截和转换,从而避免常见的安全问题,并支持更多高级用例。

它就像是数据与视图的分离模式,f-string 是直接渲染的视图,而 t-string 则保留了数据模型,允许你在最终呈现前执行各种转换规则和验证。

t-string 的设计理念体现了功能性与安全性的平衡,虽然它比 f-string 更复杂,但这种复杂性带来了更高级的可组合性和更强的安全保障。

它遵循了 Python 的"显式优于隐式"原则,通过明确分离模板结构和渲染过程,让字符串处理的每个步骤都清晰可见。

t-string 并不是一种替换 f-string 的语法,f-string 的简单易用性依然有其重要价值。

那么,在 Python 3.14 版本后,两个字符串插值方法该如何选择呢?

一句话总结:当只需简单地格式化字符串时,使用 f-string 更直接高效;而当处理不受信任的输入、需要自定义渲染逻辑、构建复杂模板系统或进行异步处理时,应选择功能更强大的 t-string。

参考资料

  1. PEP 750 – Template Strings (https://peps.python.org/pep-0750/)

  2. PEP 787 – Safer subprocess usage using t-strings (https://peps.python.org/pep-0787/)

  3. Template strings accepted for Python 3.14 (https://lwn.net/Articles/1018297/)

如果你正在寻找优质的Python文章和项目,我必须向你推荐Python潮流周刊!

它精选全网的优秀文章、教程、开源项目、软件工具、播客、视频、热门话题等丰富内容,让你紧跟技术最前沿,获取最新的第一手学习资料!

欢迎点击下方图片,了解这份全世界知识密度最高、知识广度最大的 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.

相关推荐
热点推荐
你最好确定以色列拿不到“证据”

你最好确定以色列拿不到“证据”

走读新生
2026-10-01 17:44:04
最新反转!让空姐跪下道歉的男子彻底“社死”,东航的态度很明确

最新反转!让空姐跪下道歉的男子彻底“社死”,东航的态度很明确

军情观察家
2026-10-01 16:06:40
C罗退队不到1天!4000万飞翼官宣接过葡萄牙队7号 遭质疑:蓄谋已久

C罗退队不到1天!4000万飞翼官宣接过葡萄牙队7号 遭质疑:蓄谋已久

我爱英超
2026-10-01 17:23:59
几乎全假货!利润高达2400%,为何消费者还一头扎进去争相购买?

几乎全假货!利润高达2400%,为何消费者还一头扎进去争相购买?

兵卒史
2026-10-01 14:07:08
华为Mate90系列发布,售价5999元起

华为Mate90系列发布,售价5999元起

界面新闻
2026-10-01 11:24:16
全员“反向错峰”闹尴尬!上海网友:为避出行高峰,特意30日后半夜虹桥出发,结果凌晨抵达发现,大伙全是聪明人

全员“反向错峰”闹尴尬!上海网友:为避出行高峰,特意30日后半夜虹桥出发,结果凌晨抵达发现,大伙全是聪明人

火山詩话
2026-10-01 13:51:31
苦战163分钟!中网金花德比:郑钦文2-1险些爆冷,下一轮对手出炉

苦战163分钟!中网金花德比:郑钦文2-1险些爆冷,下一轮对手出炉

侃球熊弟
2026-10-01 12:18:01
越扒越有!C罗风波发酵,葡媒曝猛料,不止要求主帅认错这么简单

越扒越有!C罗风波发酵,葡媒曝猛料,不止要求主帅认错这么简单

旧史新谭
2026-10-01 13:19:38
鸿蒙智行被小米小鹏反超,网友留言不忍直视

鸿蒙智行被小米小鹏反超,网友留言不忍直视

ZAKER新闻
2026-10-01 19:55:26
亚运10月1号赛况:韩国揽6金日本获5金,中国队拿到2金,金牌榜闹乌龙

亚运10月1号赛况:韩国揽6金日本获5金,中国队拿到2金,金牌榜闹乌龙

我是盲流
2026-10-01 19:43:14
以色列:以方今后将掌握所有飞往以色列航班飞行员身份,并进行一定程度安全审查

以色列:以方今后将掌握所有飞往以色列航班飞行员身份,并进行一定程度安全审查

新京报
2026-10-01 15:49:35
一年向12315举报1520次!某地市监局明确表态:终止对其投诉的调解处理!

一年向12315举报1520次!某地市监局明确表态:终止对其投诉的调解处理!

闪电新闻
2026-10-01 14:47:03
普京:俄罗斯不会像某些国家那样奔走世界各地,伸手卑躬屈膝地乞求施舍!泽连斯基呼吁美欧落实对俄制裁

普京:俄罗斯不会像某些国家那样奔走世界各地,伸手卑躬屈膝地乞求施舍!泽连斯基呼吁美欧落实对俄制裁

每日经济新闻
2026-10-01 10:34:54
上海94岁阿婆独自外出,摔倒流血,坚持不肯去医院!检查结果让所有人后怕…

上海94岁阿婆独自外出,摔倒流血,坚持不肯去医院!检查结果让所有人后怕…

上观新闻
2026-10-01 08:54:39
张继科训练基地学费曝光:月收费980元到4400元,学员水平越高收费越低;学员:这个资源收这个费用算很低了,“张继科亲自下场指导训练”

张继科训练基地学费曝光:月收费980元到4400元,学员水平越高收费越低;学员:这个资源收这个费用算很低了,“张继科亲自下场指导训练”

极目新闻
2026-10-01 21:40:09
用发霉陈馅做月饼,还反咬记者"别有用心",这家老字号玩死了全行业

用发霉陈馅做月饼,还反咬记者"别有用心",这家老字号玩死了全行业

西虹市闲话
2026-10-01 14:11:25
C罗大姐转发:葡萄牙不配拥有最好的人才,活该回到C罗前的平庸

C罗大姐转发:葡萄牙不配拥有最好的人才,活该回到C罗前的平庸

懂球帝
2026-10-01 04:18:07
大众新车官宣:10月12日,正式上市!

大众新车官宣:10月12日,正式上市!

科技堡垒
2026-10-01 09:18:58
最新反转!让空姐跪下道歉的男子彻底“社死”,东航的态度很明确

最新反转!让空姐跪下道歉的男子彻底“社死”,东航的态度很明确

易昂杨
2026-10-01 10:51:07
澳门赌输10亿水落石出,黄晓明不再隐瞒,原来背叛婚姻的不是杨颖

澳门赌输10亿水落石出,黄晓明不再隐瞒,原来背叛婚姻的不是杨颖

一念痴狂
2026-10-01 14:01:24
2026-10-02 00:28:49
Python猫 incentive-icons
Python猫
人生苦短,我用Python。博客:https://pythoncat.top
758文章数 8122关注度
往期回顾 全部

科技要闻

5999元起!华为Mate 90系列发布

头条要闻

美国一女囚犯被执行死刑 注射两剂药物后其"鼾声大作"

头条要闻

美国一女囚犯被执行死刑 注射两剂药物后其"鼾声大作"

体育要闻

“今天的表现,我们可以昂首离开球场”

娱乐要闻

奚梦瑶晒四太豪礼!22只龙凤镯近300万

财经要闻

智谱发上亿Token 能挽回开发者信任吗?

汽车要闻

2027款极氪001将于明年一季度上市 现款猎装同步推新配色

态度原创

艺术
游戏
教育
旅游
手机

艺术要闻

衔接时代的大师|读懂巴托尼的古典绘画美学

《战争机器》新作GS 7分:创新不足剧情令人失望

教育要闻

免中考”试点到底改了什么?

旅游要闻

南京长江路文博街区正式开街,一票通玩文博场馆,百场活动承包整月

手机要闻

瑞银:iPhone18Pro系列等待期表现平平予苹果“中性”评级

无障碍浏览 进入关怀版