Python 新的 t-strings
Python 新的 t-strings
模板字符串,也称为 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 injection 或 cross-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><script>alert('bad')</script></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。 例如,我很乐意看到 black
和 ruff
格式化 t-string 的 内容 ,并且 vscode
着色 这些内容,如果它们是一种常见的类型,如 HTML 或 SQL。
很高兴能够认识并与 Jim、Paul、Koudai、Lysandros 和 Guido 合作完成这个项目,并与 Python 社区的许多成员 在线互动,没有他们的投入,PEP 750 根本不可能完成。 我迫不及待地想看到开发者们在 t-strings 发布后用它构建出什么!