Python3.14新特性Template Strings(t-string)使用示例

Python中可能已经有很多类似模板字符串的东西,但都和 PEP 750 中的 string.templatelib 不一样

比如:string.Templatestring.Formatter/str.format()f-string%这种上古写法。

PEP 750中提到的Motivation中指出f-string的语法虽然方便,但经常会因为操作者处理SQL语句或者HTML文档时直接拼接导致出现安全漏洞。
(实话说这里确实挺抽象的。f-string没有任何问题,问题出在程序员没有对输入的内容进行预处理而直接拼接。)

>>> name = 'duzhuo'
>>> template = t'Hello,{name}'
>>> template
Template(strings=('Hello,', ''), interpolations=(Interpolation('duzhuo', 'name', None, ''),))

SQL参数化查询

from string.templatelib import Template, Interpolation
import sqlite3


def run_query(db, template: Template):
    parts = []
    params = []
    for i in template:
        if type(i) is str:
            parts.append(i)
        if type(i) is Interpolation:
            parts.append("?")
            # i.value是一个tuple
            params.append(i.value)
        query_string = "".join(parts)
    print(query_string)
    #    SELECT * FROM products
    #    WHERE is_available = ? AND category = ?
    return db.execute("".join(parts), params)


def main():
    db = sqlite3.connect("./test.db")
    is_available = 1
    category = "Home"
    template = t"""
    SELECT * FROM products
    WHERE is_available = {is_available} AND category = {category}
    """
    print(list(run_query(db, template)))


if __name__ == "__main__":
    main()

HTML转义

from html import escape
from string.templatelib import Template, Interpolation


def safe_html(template: Template) -> str:
    parts = []
    for i in template:
        if type(i) is str:
            parts.append(i)
        if type(i) is Interpolation:
            parts.append(escape(i.value))
    return "".join(parts)


def main():
    user_input1 = "duzhuo"
    user_input2 = '<script>alert("XSS Attacking")</script>'
    html_template = t"""
    <div>
    My name is <strong>{user_input1}</strong>, Here is my Message: {user_input2}
    </div>
    """
    print(safe_html(html_template))
    #
    #    <div>
    #    My name is <strong>duzhuo</strong>, Here is my Message: <script>alert("XSS Attacking")</script>
    #    </div>


if __name__ == "__main__":
    main()