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

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.

相关推荐
热点推荐
每吃一次,大脑萎缩就快一步?提醒:这4物或是老年痴呆“催化剂

每吃一次,大脑萎缩就快一步?提醒:这4物或是老年痴呆“催化剂

芹姐说生活
2026-10-01 22:22:04
每体:巴萨暂缓一线队球员宿舍建设,优先建弗里克要求的新健身房

每体:巴萨暂缓一线队球员宿舍建设,优先建弗里克要求的新健身房

懂球帝
2026-10-01 20:45:30
《伟大的长征》即将开播!首次饰演毛泽东,于和伟减重15斤

《伟大的长征》即将开播!首次饰演毛泽东,于和伟减重15斤

澎湃新闻
2026-10-01 13:34:06
杨毅:杨鸣出来没想到这么受欢迎 他肯定还有执教意愿等最合适机会

杨毅:杨鸣出来没想到这么受欢迎 他肯定还有执教意愿等最合适机会

狼叔评论
2026-10-01 18:49:04
刘某给3名好友每人每天500元,8天狂偷13吨共享单车卖废铁,最后分文未赚、亏本倒贴,西安警方:4人因涉嫌盗窃罪,已被采取刑事强制措施

刘某给3名好友每人每天500元,8天狂偷13吨共享单车卖废铁,最后分文未赚、亏本倒贴,西安警方:4人因涉嫌盗窃罪,已被采取刑事强制措施

荔枝新闻
2026-09-30 16:11:51
中式英语莫非要风靡全球了?网友:不能被外国人卡脖子!

中式英语莫非要风靡全球了?网友:不能被外国人卡脖子!

另子维爱读史
2026-10-01 19:14:59
破案了!林诗栋夺冠领奖全程黑脸,终于知道他为什么笑不出来

破案了!林诗栋夺冠领奖全程黑脸,终于知道他为什么笑不出来

观察者海风
2026-09-30 11:42:54
太多人没想到!林诗栋亚运夺冠仅过3天,王楚钦就收获一大好消息

太多人没想到!林诗栋亚运夺冠仅过3天,王楚钦就收获一大好消息

十点街球体育
2026-10-01 22:47:59
中国最诡异的4家平台公司:所有风险留给穷人,所有暴利留给自己

中国最诡异的4家平台公司:所有风险留给穷人,所有暴利留给自己

白浅娱乐聊
2026-09-22 00:31:33
10月1日油价:180度大拐弯!油价预估跌幅“再次扩大”至150元/吨

10月1日油价:180度大拐弯!油价预估跌幅“再次扩大”至150元/吨

小怪吃美食
2026-10-02 00:53:47
50岁王力宏身材杀疯了!他用6块腹肌,给所有男人上了一课

50岁王力宏身材杀疯了!他用6块腹肌,给所有男人上了一课

小方说跑步
2026-09-30 13:40:05
C罗退出国家队,听听媒体怎么说,葡媒怒斥言行不一,詹俊感叹

C罗退出国家队,听听媒体怎么说,葡媒怒斥言行不一,詹俊感叹

南海浪花
2026-10-01 11:50:46
沈梦辰在金鹰奖颁奖典礼上,礼服下穿着一双休闲小白鞋引热议

沈梦辰在金鹰奖颁奖典礼上,礼服下穿着一双休闲小白鞋引热议

韩小娱
2026-09-30 06:50:22
清纯女神火了以后成了“拜金女”,舔狗们的天又塌了!

清纯女神火了以后成了“拜金女”,舔狗们的天又塌了!

陈意小可爱
2026-10-02 00:03:39
耿同学揭露后,知名大学教授离职!校方回应

耿同学揭露后,知名大学教授离职!校方回应

双一流高校
2026-10-02 00:25:53
震惊!网传某半导体大厂号召全员降薪共渡难关,一同降薪20%,财报曝光:老总年薪大涨33%,年薪反倒从600万涨至800万

震惊!网传某半导体大厂号召全员降薪共渡难关,一同降薪20%,财报曝光:老总年薪大涨33%,年薪反倒从600万涨至800万

火山詩话
2026-09-27 13:25:11
C罗好友:热苏斯承诺公开道歉却让C罗处境更糟,他才爆发

C罗好友:热苏斯承诺公开道歉却让C罗处境更糟,他才爆发

懂球帝
2026-10-01 08:22:06
网友吐槽,麦当劳都快变成垃圾场了,中途没人收拾,吃完也没人收拾,到底因为啥?

网友吐槽,麦当劳都快变成垃圾场了,中途没人收拾,吃完也没人收拾,到底因为啥?

眼光很亮
2026-09-29 12:56:10
斯诺克决出3席8强!2场5-2,罗伯逊囧哥翻车,赵心童终结者被横扫!

斯诺克决出3席8强!2场5-2,罗伯逊囧哥翻车,赵心童终结者被横扫!

刘姚尧的文字城堡
2026-10-01 17:43:18
梁洛施和男友马浴柯出席路演,十指紧扣大方秀恩爱,尽显甜蜜

梁洛施和男友马浴柯出席路演,十指紧扣大方秀恩爱,尽显甜蜜

阿废冷眼观察所
2026-10-02 00:30:52
2026-10-02 02:19:00
Python猫 incentive-icons
Python猫
人生苦短,我用Python。博客:https://pythoncat.top
758文章数 8122关注度
往期回顾 全部

科技要闻

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

头条要闻

桂林市文促会深夜发布致歉信:向阿丘诚恳致歉

头条要闻

桂林市文促会深夜发布致歉信:向阿丘诚恳致歉

体育要闻

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

娱乐要闻

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

财经要闻

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

汽车要闻

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

态度原创

手机
房产
家居
本地
公开课

手机要闻

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

房产要闻

4000+/平!华侨城,直接把海口楼市的地板给掀了!

家居要闻

2026建博会(广州) 公装联探展交流活动

本地新闻

中秋逛白塔寺,体验国医妙荟雅集

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版