PEP 750 在前些日正式被通过,鉴于截止本文发出 CPython 3.14 仍未包罗相干实现,故本文仅对 PEP 750 举行翻译。
摘要
本提案引入了模板字符串(Template Strings),用于自定义字符串处置惩罚。模板字符串是 f-strings 的泛化形式,使用 t 前缀代替f。与 f-strings 直接生成 str 不同,t-strings 生成一个新的 Template 类型,答应开发者在值被组合前访问原始字符串及其插值内容。这为Python带来了原生的灵活字符串处置惩罚能力,支持安全检查、网页模板、领域特定语言等场景。- template: Template = t"Hello {name}"
复制代码 与其他 Python 增强提案的关系
Python 在 Python 3.6 中通过 PEP 498 引入了 f-字符串。随后在 PEP 701 中对语法举行了正式化,并放宽了一些限定。本 PEP 基于 PEP 701 。
在 PEP 498 出现的同时,PEP 501 被撰写以提供“i-strings”——即,“插值模板字符串”。该 PEP 由于对 f-strings 的进一步经验而被推迟。该提案的工作于 2023 年 3 月由不同的作者规复,引入了“t-strings”作为模板字面量字符串,并基于 PEP 701 构建。
动机
Python f-strings 易于使用且非常受接待。然而,随着时间的推移,开发者发现它不适合某些用途。特别地,f-strings 并未提供了一种在最终字符串组合之前拦截和转换插值值的方法。
因此,不恰当地使用 f-字符串可能会导致安全漏洞。例如,用户执行 SQL 查询时,可能会尝试使用 f-strings 将值嵌入到 SQL 表达式中,这可能会导致 SQL 注入攻击。大概,开发职员在构建 HTML 时,可能会包罗未转义的用户输入,从而导致跨站脚本 (XSS) 漏洞。更广泛地说,无法在将插值值组合到最终字符串之前对其举行转换,导致 f-strings 无法在更复杂的字符串处置惩罚任务中使用。
模板字符串通过为开发者提供对字符串及其插值的访问权限来解决这些问题。
例如,假设我们想要生成一些 HTML。使用模板字符串,我们可以定义一个 html() 函数,答应我们自动处置惩罚内容:- evil = ""
- template = t"<p>{evil}</p>"
- assert html(template) == "<p><script>alert('evil')</script></p>"
复制代码 同样,我们假设的 html() 函数可以让开发者使用字典轻松地为 HTML 元素添加属性:- attributes = {"src": "https://www.cnblogs.com/shrubbery.jpg", "alt": "looks nice"}
- template = t"<img {attributes} />"
- assert html(template) == '<img src="https://www.cnblogs.com/shrubbery.jpg" alt="looks nice" />'
复制代码 这两个示例都无法使用 f-strings 实现。
规范
模板字符串字面量
本提案引入了一个新的字符串前缀 t ,用于定义模板字符串字面量。这些字面量解析为 Template 类型。可以从标准库 string.templatelib 模块找到该类型。
下面是一个示例:- from string.templatelib import Template
- template = t"This is a template string."
- assert isinstance(template, Template)
复制代码 模板字符串字面量支持 PEP 701 的完备语法。这包罗能够在插值中嵌套模板字符串的能力,以及使用全部有效的引号( ' 、 " 、 ''' 和 """ )。与其他字符串前缀一样, t 前缀必须紧接在引号之前。与 f-strings 一样,t-strings 同时支持小写 t 和大写 T 前缀。与 f-strings 一样,t-strings 不能与 u 或 b 前缀结合使用。
此外,f-strings 和 t-strings 不能结合使用,因此 ft 前缀无效。t-strings 可以与 r 前缀结合;有关更多信息,请参见原始模板字符串部门。
模板类型
string.templatelib.Template
模板字符串为一个新的不可变类型实例。- class Template:
- strings: tuple[str, ...]
- """
- 模板的字符串部分的非空元组,
- 有N+1个元素,其中N是模板内插入内容的数量。
- """
- interpolations: tuple[Interpolation, ...]
- """
- 模板的插值部分的元组。
- 如果没有插值,这将是一个空元组。
- """
- def __new__(cls, *args: str | Interpolation):
- """
- 创建一个新的模板实例。
- 参数可以以任何顺序提供。
- """
- ...
- @property
- def values(self) -> tuple[object, ...]:
- """
- 返回一个元组,包含模板中每个插值的`value`属性
- 如果没有插值,这将是一个空元组。
- """
- ...
- def __iter__(self) -> Iterator[str | Interpolation]:
- """
- 遍历模板中的字符串部分和插值。
- 它们可能以任何顺序出现,不包含空字符串。
- """
- ...
复制代码 strings 和 interpolations 属性分别提供了对字符串部门和插值部门的访问:- name = "World"
- template = t"Hello {name}"
- assert template.strings[0] == "Hello "
- assert template.interpolations[0].value == "World"
复制代码 插值类型
string.templatelib.Interpolation
插值类型表现模板字符串中的插值。- class Interpolation:
- value: object
- expression: str
- conversion: Literal["a", "r", "s"] | None
- format_spec: str
- __match_args__ = ("value", "expression", "conversion", "format_spec")
- def __new__(
- cls,
- value: object,
- expression: str,
- conversion: Literal["a", "r", "s"] | None = None,
- format_spec: str = "",
- ):
- ...
复制代码 插值类型是浅不可变的,其属性无法重新赋值。
value 属性是插值的盘算结果,expression 属性是插值的原始表达式。- name = "World"
- template = t"Hello {name}"
- assert template.interpolations[0].value == "World"
- assert template.interpolations[0].expression == "name"
复制代码 我们预计在大多数模板处置惩罚代码中不会使用 expression 属性。该属性是为了完备性以及在调试和反向工程中使用而提供的。有关怎样处置惩罚模板字符串的更多信息,请参阅“常见在处置惩罚模板中看到的模式”部门和“示例”部门。
conversion 属性用于可选的类型转换,可以是 r 、 s 或 a ,分别对应 repr() 、 str() 和 ascii() 转换。与 f-strings 相同,不支持其他转换。若未指定转换,则值为 None 。- name = "World"
- template = t"Hello {name!r}"
- assert template.interpolations[0].conversion == "r"
复制代码 format_spec 属性指定格式规范。就像 f-strings 一样,这是一个字符串,定义了怎样呈现值。若未指定格式,则值为空字符串。- value = 42
- template = t"Value: {value:.2f}"
- assert template.interpolations[0].format_spec == ".2f"
复制代码 格式规范在 f-strings 中可以包罗内插,这在模板字符串中也是答应的。- value = 42
- precision = 2
- template = t"Value: {value:.{precision}f}"
- assert template.interpolations[0].format_spec == ".2f"
复制代码 与 f-strings 不同,处置惩罚模板的代码需要自行决定怎样解释 conversion 和 format_spec 属性。这样的代码不需要使用这些属性,但当这些属性存在时,应该被尊重,并尽可能匹配 f-strings 的举动。例如,如果模板字符串使用了 {value:.2f} ,在处置惩罚时没有将值舍入到两位小数,这将是令人惊讶的。
模板类型 values 属性
Template.values 属性是访问模板中每个 Interpolation 的 value 属性的快捷方式,并等价于:- @property
- def values(self) -> tuple[object, ...]:
- return tuple(i.value for i in self.interpolations)
复制代码 迭代模板类型内容
Template.__iter__() 方法提供了一种简朴的方式来访问模板的完备内容。它按出现顺序提供字符串部门和插值,省略空字符串。- assert list(t"") == []
- assert list(t"Hello") == ["Hello"]
- name = "World"
- template = t"Hello {name}!"
- contents = list(template)
- assert len(contents) == 3
- assert contents[0] == "Hello "
- assert contents[1].value == "World"
- assert contents[1].expression == "name"
- assert contents[2] == "!"
复制代码 未完待续
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |