Python 3.14 t-string 要来了,它与 f-string 有何不同?
zhezhongyun 2025-05-30 18:57 28 浏览
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)) # 输出:<class 'str'>
print(formatted) # 输出:Hello World!
# t-string 语法
templated = t"Hello {name}!"
print(type(templated)) # 输出:<class 'string.templatelib.Template'>
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 因其简洁易用而广受欢迎,但它也存在一些无法忽视的局限性:
- 安全隐患:当直接将用户输入嵌入到 SQL 查询、HTML 内容或系统命令中时,f-string 可能导致注入攻击
- 缺乏转换能力:f-string 没有提供在字符串组合前拦截和转换插入值的机制
- 灵活性不足:对于复杂的字符串处理任务,f-string 的能力有限
提升字符串处理的安全性
不谨慎使用 f-string,可能导致安全漏洞:
# 使用 f-string 的不安全示例(SQL 注入风险)
sql_query = f"SELECT * FROM users WHERE name = '{user_input}'"
# 使用 f-string 的不安全示例(XSS 风险)
html_content = f"<div>{user_input}</div>"
而 t-string 允许开发者在字符串组合前对插值进行适当处理:
# 使用 t-string 的安全示例
evil = "<script>alert('evil')</script>"
template = t"<p>{evil}</p>"
# 可以定义处理函数来转义内容
assert html(template) == "<p><script>alert('evil')</script></p>"
增强字符串处理的灵活性
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 = ["<data>"]
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("</data>")
return"\n".join(parts)
# 同一个模板,不同的输出格式
print(standard_renderer(template)) # 输出: 用户 Python猫 的年龄是 18
print(json_renderer(template)) # 输出: {"name": "Python猫", "age": 18}
print(xml_renderer(template)) # 输出: <data>\n <name>Python猫</name>\n <age>18</age>\n</data>
这种灵活性是 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 的异同点
相似之处
- 基本语法:二者都使用花括号 {} 作为插值表达式的分隔符
- 表达式求值:都支持在花括号中放置任意 Python 表达式
- 格式说明符:都支持格式说明符(如 .2f)和转换说明符(如 !r)
- 引号支持:都支持所有有效的引号标记('、"、'''、""")
- 大小写不敏感前缀:t 和 T 都是有效的,就像 f 和 F
不同之处
- 返回类型:f-string 直接返回 str 类型,而 t-string 返回 Template 类型
- 求值时机:f-string 在定义时立即求值,t-string 提供延迟求值能力
- 结构访问:t-string 允许访问原始模板的结构(字符串部分和插值部分)
- 处理模型: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 = "<script>alert('XSS')</script>"
safe_html = html(t"<div>{user_input}</div>")
# 输出: <div><script>alert('XSS')</script></div>
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 = "<script>alert('evil')</script>"
template = t"用户输入: {user_input}"
print(smart_renderer(template, context="html")) # 输出: 用户输入: <script>alert('evil')</script>
# 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)) # <class 'str'> - 只是普通字符串
# t-string的嵌套:保留完整结构信息
inner_t = t"inner {value}"
outer_t = t"outer {inner_t}"
print(type(outer_t)) # <class 'string.templatelib.Template'>
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。
参考资料
- PEP 750 – Template Strings (https://peps.python.org/pep-0750/)
- PEP 787 – Safer subprocess usage using t-strings (https://peps.python.org/pep-0787/)
- Template strings accepted for Python 3.14 (https://lwn.net/Articles/1018297/)
相关推荐
- EU Said to Accept a 10% U.S. Universal Tariff while Seeking Exemptions for Key Sectors
-
TMTPOST--TheEuropeanUnionmaymakeconcessionstosecureexemptionsfromtariffsonkeysectors...
- 抖音品质建设 - iOS启动优化《实战篇》
-
前言启动是App给用户的第一印象,启动越慢,用户流失的概率就越高,良好的启动速度是用户体验不可缺少的一环。启动优化涉及到的知识点非常多,面也很广,一篇文章难以包含全部,所以拆分成两部分:原理和实战...
- 荷兰引进美国诗人阿曼达·戈尔曼诗作,因译者肤色遭抵制
-
记者|刘亚光阿曼达在拜登就职典礼上朗诵诗歌。图源:PatrickSemansky/AssociatedPress阿曼达·戈尔曼(AmandaGorman)出生于1998年,自小患有语言障碍,...
- EU and U.S. Upbeat on Trade Deal Ahead of July Deadline
-
TMTPOST--TheEuropeanUnionandtheUnitedStatesseemupbeatontheirtradeagreementtoavoidtr...
- “过期食品”英文怎么说?(过期食品)
-
在购买食品时,我们都会特别留意一下食物的保质期有多久,是否新鲜,以免买到过期的商品。TheafternoonteaspreadatThePeninsulaBoutiqueandCaf...
- 世界首富撩妹露骨短信遭曝光 网友评论亮了
-
原标题:世界首富如何撩妹?亚马逊创始人贝索斯给情妇的露骨短信曝光这周最大的一个瓜,可能就是亚马逊首席执行官杰夫·贝佐斯(JeffBezos)与妻子麦肯齐(MacKenzie)离婚的惊人消息。紧接...
- 征收熊孩子“尖叫费”不合理?店主回怼网友
-
爱尔兰一家很受欢迎的咖啡馆要收“孩童尖叫费”,网友们。。。爱尔兰一咖啡店店主5月4日在脸书发帖,表示要向带有吵闹孩童的顾客多收15%的额外费用,引发了大批网友的议论。原贴内容如下:图viaFaceb...
- Rationality, objectivity and pragmatism win the day in Geneva to benefit of all
-
ApressbriefingisheldbytheChinesesidefollowingtheChina-UShigh-levelmeetingoneconomica...
- Dify「模板转换」节点终极指南:动态文本生成进阶技巧(附代码)Jinja2引擎解析|6大应用场景实战
-
这篇文章是关于Dify「模板转换」节点的终极指南,解析了基于Jinja2模板引擎的动态文本生成技巧,涵盖多源文本整合、知识检索结构化、动态API构建及个性化内容生成等六大应用场景,助力开发者高效利用模...
- 微软 Edge 浏览器 96.0.4664.93 稳定版发布:修复大量安全问题
-
IT之家12月12日消息,据外媒mspoweruser消息,微软12月11日为Edge浏览器推出了96.0.4664.93稳定版。该版本没有增加新功能,而是修复了大量漏洞,...
- HarmonyOS NEXT仓颉开发语言实战案例:健身App
-
各位好,今日分享一个健身app的首页:这个页面看起比之前的案例要稍微复杂一些,主要在于顶部部分,有重叠的背景,还有偏移的部分。重叠布局可以使用Stack容器实现,超出容器范围的偏移可以使用负数间距来实...
- 如果使用vue3.0实现一个modal,你会怎么设计?
-
这是个很好的问题!设计一个Vue3.0Modal时,我建议按照可复用、高扩展、简洁的原则来实现。下面我给你一个清晰的设计思路,涵盖组件拆分、使用方式以及Vue3中特性(如Telepor...
- 在进行APP切图的前,我们需要做什么?
-
切图是个技术活,小伙伴们千万不能忽视切图的重要性噢,前文介绍了设计的七大元素,那么我们现在来看看在切图之前,我们需要做什么呢?。1、和客户端的技术沟通好用不同的框架来实现的时候,图会有不一样的切法。...
- 独立开发问题记录-margin塌陷(独立提出历史问题)
-
一、概述往事如风,一周就过去了。上周在Figma里指点江山,这周在前端代码里卑微搬砖。回想上周,在Figma中排列组合,并且精确到1像素。每设计出一个页面,成就感就蹭蹭往上涨。没想到还没沾沾自喜多久,...
- 循序渐进Vue+Element 前端应用开发(8)—树列表组件的使用
-
在我前面随笔《循序渐进VUE+Element前端应用开发(6)---常规Element界面组件的使用》里面曾经介绍过一些常规的界面组件的处理,主要介绍到单文本输入框、多文本框、下拉列表,以及按钮...
- 一周热门
- 最近发表
-
- EU Said to Accept a 10% U.S. Universal Tariff while Seeking Exemptions for Key Sectors
- 抖音品质建设 - iOS启动优化《实战篇》
- 荷兰引进美国诗人阿曼达·戈尔曼诗作,因译者肤色遭抵制
- EU and U.S. Upbeat on Trade Deal Ahead of July Deadline
- “过期食品”英文怎么说?(过期食品)
- 世界首富撩妹露骨短信遭曝光 网友评论亮了
- 征收熊孩子“尖叫费”不合理?店主回怼网友
- Rationality, objectivity and pragmatism win the day in Geneva to benefit of all
- Dify「模板转换」节点终极指南:动态文本生成进阶技巧(附代码)Jinja2引擎解析|6大应用场景实战
- 微软 Edge 浏览器 96.0.4664.93 稳定版发布:修复大量安全问题
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- HTML button formtarget 属性 (30)
- CSS 水平对齐 (Horizontal Align) (30)
- opacity 属性 (32)