Python 3.14 の t-string(PEP 750)を実際に動かして安全なテンプレートを作る

Python 3.14(2025 年 10 月リリース)で template string(t-string, PEP 750) が入った。見た目は f-string の親戚だが、目的がまったく違う。f-string が「即座に文字列を組み立てて返す」のに対し、t-string は組み立てる前の材料(静的部分と補間値)を保持した Template オブジェクトを返す。この違いが、XSS 対策や SQL の安全な組み立てといった「補間値を特別扱いしたい」場面で効く。

f-string と t-string の違い

1
2
3
name = "world"
f"Hello, {name}" # -> "Hello, world"(ただの str)
t"Hello, {name}" # -> Template オブジェクト(まだ文字列化されていない)

f-string は評価した瞬間に str になるので、補間された値がどこから来たのか(ユーザー入力か定数か)を後から区別できない。t-string は Template を返し、静的な文字列部分と補間部分を分けて持っているため、補間値にだけエスケープ処理をかける、といった加工ができる。

Template の主なプロパティは次のとおり。

  • .strings: 補間の間にある静的な文字列部分のタプル
  • .values: 補間された値のタプル
  • .interpolations: 各補間の情報(Interpolation オブジェクト。.value.expression を持つ)

PEP 750 は t-string の構文だけを定義していて、標準ライブラリは Template を「どう処理するか」までは提供しない。つまり処理系(プロセッサ)は自分で書くか、サードパーティを使う。逆に言えば、用途に合わせたテンプレート処理を自作できるのが強みだ。

実際に試す

前提: Python 3.14 以上(この記事は 3.14.4 で検証)。バージョンを確認する。

1
2
python --version
# 例: Python 3.14.4

pyenv を使うなら次で用意できる。

1
2
pyenv install 3.14.4
pyenv shell 3.14.4

Template を分解して中身を見る

tstrings.py として保存する。

1
2
3
4
5
6
7
8
9
10
11
from string.templatelib import Template, Interpolation
from html import escape

name = "Pythonista"
day = "Friday"
t = t"Hello, {name}! Today is {day}."

print("type:", type(t).__name__)
print("strings:", t.strings)
print("values:", t.values)
print("interpolations:", [i.expression for i in t.interpolations])

実行する。

1
python tstrings.py

期待される出力。

1
2
3
4
type: Template
strings: ('Hello, ', '! Today is ', '.')
values: ('Pythonista', 'Friday')
interpolations: ['name', 'day']

.strings に静的部分、.values に補間値、.interpolations の各要素に元の式(name, day)が入っているのが分かる。f-string ではこの分解ができない。

補間値だけを HTML エスケープする自作プロセッサ

t-string の実用例が「テンプレート内のユーザー入力だけを安全化する」ことだ。Templatefor で回すと、静的部分は str、補間部分は Interpolation として順に取り出せる。補間部分にだけ html.escape をかければ、静的な HTML はそのまま、入力値だけがエスケープされる。

同じ tstrings.py に追記する。

1
2
3
4
5
6
7
8
9
10
11
12
def render_html(template: Template) -> str:
parts: list[str] = []
for item in template:
if isinstance(item, str):
parts.append(item) # 静的部分はそのまま
else: # Interpolation
parts.append(escape(str(item.value))) # 補間値だけエスケープ
return "".join(parts)

user_input = '<script>alert("xss")</script>'
page = t"<p>Comment: {user_input}</p>"
print("safe:", render_html(page))

再実行すると、次の行が加わる。

1
safe: <p>Comment: &lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;</p>

<p> タグは静的部分なのでそのまま残り、ユーザー入力の <script> はエスケープされている。f-string で f"<p>Comment: {user_input}</p>" と書くと入力がそのまま埋め込まれてしまうのと対照的だ。同じ発想で、SQL の値プレースホルダ化やシェルコマンドのクオートなど「補間値だけを安全化したい」処理を、テンプレートの見た目を保ったまま書ける。

まとめ

t-string は「文字列を返さず、材料を保持した Template を返す」という一点で f-string と決定的に違う。この性質のおかげで、補間値だけにエスケープや検証をかけるプロセッサを自作でき、テンプレートの可読性と安全性を両立できる。Python 3.14 が手元にあれば、上のコードをそのまま実行して Template の分解とエスケープ処理を確かめてほしい。

出典


Python 3.14 の t-string(PEP 750)を実際に動かして安全なテンプレートを作る
https://blog.hashito.biz/2026/07/11/try-python-3-14-t-strings-pep-750/
著者
hashito
作成日
2026年7月11日
著作権