Python 新的 t-strings

2025年4月11日

模板字符串,也称为 t-strings,已被 正式接受 为 Python 3.14 的一项特性,预计将于 2025 年底发布。🎉

我感到很兴奋;t-strings 为 Python 中更安全、更灵活的字符串处理打开了大门。

t-strings 的核心思想是什么?

自从在 Python 3.6 中引入以来,f-strings 已经成为一种 非常 流行的字符串格式化方式。它们简洁、可读且功能强大。

事实上,它们 非常 令人喜爱,以至于许多开发者在所有情况下都使用 f-strings……即使在不应该使用的时候!

唉,f-strings 经常被危险地(错误地)用于格式化包含用户输入的字符串。 我见过 f-strings 被用于 SQL (f"SELECT * FROM users WHERE name = '{user_name}'") 和 HTML (f"<div>{user_name}</div>")。 这些是不安全的! 如果 user_name 包含恶意值,则可能导致 SQL injectioncross-site scripting

模板字符串是 Python 的 f-strings 的一种 泛化 。 f-strings 会立即变成一个字符串,而 t-strings 则会计算出一个新类型 string.templatelib.Template

from string.templatelib import Template
name = "World"
template: Template = t"Hello {name}!"

重要的是,Template 实例 不是 字符串。 Template 类型不提供自己的 __str__() 实现,也就是说,调用 str(my_template) 不会返回有用的值。 模板 必须 在使用前进行处理;该处理代码可以由开发人员编写,也可以由库提供,并且可以安全地转义动态内容。

我们可以想象一个库提供一个 html() 函数,该函数接受一个 Template 并返回一个安全转义的字符串:

evil = "<script>alert('bad')</script>"
template = t"<p>{evil}</p>"
safe = html(template)
assert safe == "<p>&lt;script&gt;alert('bad')&lt;/script&gt;</p>"

当然,t-strings 的用途不仅仅在于安全性;它们还允许更灵活的字符串处理。 例如,html() 函数可以返回一种新类型 HTMLElement。 它也可以接受 HTML 本身中的各种有用的替换:

attributes = {"src": "roquefort.jpg", "alt": "Yum"}
template = t"<img {attributes} />"
element = html(template)
assert str(element) == "<img src='roquefort.jpg' alt='Yum' />"

如果您使用过 JavaScript,那么 t-strings 可能会让您感到熟悉。 它们是 Python 中与 JavaScript 的 tagged templates 对应的概念。

如何使用 t-strings?

为了支持处理,Template 使开发人员可以在将字符串及其内插值组合成最终字符串 之前 访问它们。

Template.strings.values 属性返回元组:

name = "World"
template = t"Hello {name}!"
assert template.strings == ("Hello ", "!")
assert template.values == (name,)

字符串的数量总是比值的数量多一个(可能为空)。 也就是说,t"".strings == ("",) 并且 t"{name}".strings == ("", "")

作为一种快捷方式,也可以迭代 Template

name = "World"
template = t"Hello {name}!"
contents = list(template)
assert contents[0] == "Hello "
assert contents[1].value == name
assert contents[2] == "!"

编写复杂处理代码的开发人员还可以访问每个插值的详细信息:

name = "World"
template = t"Hello {name!s:>8}!"
assert template.interpolations[0].value == name
assert template.interpolations[0].expression == "name"
assert template.interpolations[0].conversion == "s"
assert template.interpolations[0].format_spec == ">8"

除了支持字面量形式(t"foo")之外,还可以直接实例化 Template

from string.templatelib import Template, Interpolation
template = Template(
	"Hello ",
	Interpolation(value="World", expression="name"),
	"!"
)

字符串和插值可以以任何顺序提供给 Template 构造函数。

一个简单的 t-string 示例

假设我们想要编写代码将所有替换的单词转换为 Pig Latin 语。 这只需要一个简单的函数:

def pig_latin(template: Template) -> str:
	"""Convert a Template to pig latin."""
	result = []
	for item in template:
		if isinstance(item, str):
			result.append(item)
		else:
			word = item.value
			if word and word[0] in "aeiou":
				result.append(word + "yay")
			else:
				result.append(word[1:] + word[0] + "ay")
	return "".join(result)
name = "world"
template = t"Hello {name}!"
assert pig_latin(template) == "Hello orldway!"

这是一个愚蠢的例子;如果您想看一些 不那么 愚蠢的例子,请查看 PEP 750 示例库

t-strings 发布后接下来会发生什么?

T-strings 是一项强大的新功能,它将使 Python 字符串处理更加安全和灵活。 我希望看到它们被用于各种库和框架中,尤其是那些处理用户输入的库和框架。

此外,我希望工具生态系统能够适应并支持 t-strings。 例如,我很乐意看到 blackruff 格式化 t-string 的 内容 ,并且 vscode 着色 这些内容,如果它们是一种常见的类型,如 HTML 或 SQL。

很高兴能够认识并与 JimPaulKoudaiLysandrosGuido 合作完成这个项目,并与 Python 社区的许多成员 在线互动,没有他们的投入,PEP 750 根本不可能完成。 我迫不及待地想看到开发者们在 t-strings 发布后用它构建出什么!