最近 Python 3.14 のリリースノートをぼんやり眺めていたら、「t-strings」という見慣れない記法が目に入りました。f"..." に似ているのに、なんか違う……? 気になって調べてみたら、思ったよりずっと面白い機能だったのでまとめてみました。
SQLインジェクションとかXSSとか、セキュリティ系の話に弱い自分でも「あ、これ便利じゃん」と思えたので、同じく「なんとなく聞いたことある」くらいの人の参考になれば嬉しいです。
この記事でわかること
- t-strings とは何か、f-strings との違い
TemplateオブジェクトとInterpolationの構造- 基本的な書き方・使い方
- 実用的なユースケース(HTML エスケープ・構造化ログ)
- f-strings と使い分ける判断基準
Python 3.14 とは?まずざっくり背景だけ
Python 3.14 は 2025年10月7日にリリースされたメジャーバージョンです。2025年12月2日には最初のメンテナンスリリースとなる 3.14.1 も公開されています。(ちなみに現時点だと 3.14.3 が 2026年2月3日にリリース済みっぽいです)
今回の目玉機能は大きく分けて以下の3つです(他にもいろいろあります)。
- PEP 750:テンプレート文字列(t-strings)の追加
- PEP 649:アノテーションの遅延評価(型ヒントの前方参照問題が解決)
- PEP 779:フリースレッド(free-threaded)Python を「公式サポート」扱いにするための基準を明文化
今回はこの中でも特に「え、これどういうこと?」となった t-strings に絞って深掘りしていきます。
t-strings って何?f-strings との決定的な違い
見た目は f-strings とほぼ同じ
t-strings の書き方は f"..." の f を t に変えるだけです。T(大文字)でも動きます。
# f-strings(Python 3.6〜)
name = "ニャンチュー"
result_f = f"こんにちは、{name}さん"
print(result_f) # こんにちは、ニャンチューさん
print(type(result_f)) # <class 'str'>
# t-strings(Python 3.14〜)
result_t = t"こんにちは、{name}さん"
print(result_t) # Template(strings=('こんにちは、', 'さん'), interpolations=(Interpolation('ニャンチュー', 'name', None, ''),))
print(type(result_t)) # <class 'string.templatelib.Template'>
f-strings(f"...")は即座に文字列(str)を返しますが、t-strings(t"...")は Template オブジェクトを返します。静的なテキスト部分と補間部分が即座に結合されることなく別々に保持されます。これが t-strings の本質的な特徴です。
Template オブジェクトの構造
Template オブジェクトは、文字列を「静的なテキスト部分」と「補間(変数)部分」に分けて保持しています。実際に中身を確認してみるとこんな感じです。
from string.templatelib import Template, Interpolation
country = "日本"
count = 47
tmpl = t"{country} には {count} 都道府県があります"
print(tmpl.strings) # ('', ' には ', ' 都道府県があります')
print(tmpl.values) # ('日本', 47)
print(tmpl.interpolations) # (Interpolation('日本', 'country', None, ''), Interpolation(47, 'count', None, ''))
各 Interpolation オブジェクトが持つ属性はこんな感じです。
.value:変数の値(評価済み).expression:式(文字列として。変数名に限らず任意の式になり得ます).conversion:変換フラグ(!r/!s/!aなど。なければNone).format_spec:フォーマット指定子(:.2fとかの部分)
Template をイテレートする
Template オブジェクトはイテラブルで、静的テキスト(str)と Interpolation を交互に取り出せます。Interpolation 型は「この部分は変数の置き換えで生成された」ということを示す型です。
food = "カレー"
tmpl = t"今日のごはんは {food} です!"
for part in tmpl:
if isinstance(part, str):
print("テキスト部分:", part)
elif isinstance(part, Interpolation):
print("変数部分:", part.value)
# テキスト部分: 今日のごはんは
# 変数部分: カレー
# テキスト部分: です!
「文字列として即座に完成させない」ことで、補間前の値を検査したり加工したりできるわけです。これが f-strings にはできなかったことです。
t-strings の使い方:Template を文字列に変換する
シンプルなレンダー関数を作る
t-strings 単体では文字列を出力しないので、最終的に文字列に変換する処理(レンダー関数)を自分で書く必要があります。まずは一番シンプルなものから。
from string.templatelib import Template, Interpolation
def render(tmpl: Template) -> str:
"""Template を素直に文字列化するだけの関数"""
parts = []
for part in tmpl:
if isinstance(part, Interpolation):
parts.append(str(part.value))
else:
parts.append(part)
return "".join(parts)
name = "ニャンチュー"
age = 28
result = render(t"{name} は {age} 歳です")
print(result) # ニャンチュー は 28 歳です
「わざわざ関数書くの面倒くさい……」と思いますよね。自分も最初そう思いました。でも、この「一手間」こそが t-strings の強みを生かす部分なので、もう少しお付き合いください。
フォーマット指定子も使える
f-strings と同様に :.2f などのフォーマット指定子や !r などの変換フラグも使えます。Interpolation の属性でそれぞれ取り出せます。
pi = 3.14159
tmpl = t"π ≈ {pi:.4f}"
print(tmpl.interpolations[0].format_spec) # '.4f'
print(tmpl.interpolations[0].value) # 3.14159
t-strings の実用的なユースケース
ここからが本番です。t-strings が「ただ似てるだけの機能」じゃないとわかる使い方を見ていきます。
ユースケース①:HTML エスケープで XSS を防ぐ
f-strings でユーザー入力をそのまま HTML に埋め込んでしまうと、XSS(クロスサイトスクリプティング)の脆弱性につながります。t-strings を使えば、Template インスタンスが静的文字列と補間部分を実行時に区別できるため、ユーザー入力のサニタイズに活用できます。
from string.templatelib import Template, Interpolation
import html as html_module
def safe_html(tmpl: Template) -> str:
"""補間部分の値を HTML エスケープして文字列を生成する"""
parts = []
for part in tmpl:
if isinstance(part, Interpolation):
# ユーザー入力などの変数部分だけエスケープ
parts.append(html_module.escape(str(part.value)))
else:
# テンプレートの静的部分はそのまま
parts.append(part)
return "".join(parts)
# 悪意のある入力を想定(※「<script>...」みたいな生の入力が来る前提)
user_input = "<script>alert('XSS攻撃!')</script>"
# f-strings だと危ない(= エスケープせず埋め込むと、そのまま解釈され得る)
bad = f"<p>{user_input}</p>"
print(bad)
# t-strings + safe_html なら補間部分だけをエスケープできる
safe = safe_html(t"<p>{user_input}</p>")
print(safe)
# <p><script>alert('XSS攻撃!')</script></p> ← エスケープ済み
静的なテキスト(<p> タグ部分)はテンプレートの作者が書いたものなので信頼できる。でも補間部分はユーザー入力なので信頼できない。その区別を自動で持てるのが t-strings の強みです。
ユースケース②:構造化ログ(センシティブ情報のマスク)
ログにパスワードや API キーが平文で残ってしまう……というのは地味に怖いミスです。t-strings を使えば、補間部分かどうかを判定しながら値をマスクする処理をコードレベルで実装できます。
from string.templatelib import Template, Interpolation
MASK = "*"
def mask_sensitive(tmpl: Template) -> str:
"""補間値をアスタリスクでマスクしてログ出力用文字列を生成する"""
masked = ""
for part in tmpl:
if isinstance(part, Interpolation):
# 値の文字数分だけアスタリスクに置き換える
masked += MASK * len(str(part.value))
else:
masked += part
return masked
user = "nyan_chu"
password = "super_secret_password"
log_msg = mask_sensitive(t"ログイン試行: ユーザー={user}, パスワード={password}")
print(log_msg)
# ログイン試行: ユーザー=********, パスワード=*********************
通常の f-strings だと「ログに残さないように気をつける」という人間側のルールに頼るしかないですが、t-strings ならコードレベルで強制できるのがいいなと思いました。
ユースケース③:構造化ログ(式文字列と値をセットで記録)
Interpolation オブジェクトは .expression 属性で式(文字列)も持っているので、変数名と値のペアをそのままログに出力することもできます。
import json
from string.templatelib import Template, Interpolation
def structured_log(tmpl: Template) -> str:
"""メッセージ + JSON フィールドとしてログ出力する"""
message_parts = []
fields = {}
for part in tmpl:
if isinstance(part, Interpolation):
message_parts.append(str(part.value))
# expression は「式」なので、ここではキーに使う前提で軽く制約した方が安全
fields[part.expression] = part.value
else:
message_parts.append(part)
message = "".join(message_parts)
return f"{message} | {json.dumps(fields, ensure_ascii=False)}"
action = "deploy"
env = "staging"
version = "v2.3.1"
print(structured_log(t"アクション: {action}、環境: {env}、バージョン: {version}"))
# アクション: deploy、環境: staging、バージョン: v2.3.1 | {"action": "deploy", "env": "staging", "version": "v2.3.1"}
ログパース・アラート・ダッシュボードへの表示がシンプルになって、余分なパースや重複処理が不要になるのが嬉しいポイントです。(実務で使ったことはまだないですが、個人的にはかなり魅力的に映ってます)
f-strings と t-strings、どっちを使うべき?
使い分けの考え方
f-strings は引き続き、手軽で高速な文字列フォーマットのための主役です。デバッグ用の print や、ちょっとしたメッセージ生成なら f-strings の方がシンプルで速い。t-strings は特にライブラリ作者にとって有用な機能っぽいです。
t-strings が光るのはこういったケースかなと思います。
- ユーザー入力を HTML / SQL に埋め込む(XSS・SQLインジェクション対策)
- センシティブな値を含む可能性があるログ(マスキング・フィルタリング)
- ライブラリ・フレームワーク開発(テンプレート処理系を自作したい人向け)
- 補間値を後から検査・加工する必要があるあらゆるケース
比較表でまとめると
- 📝 返り値:f-strings →
str/ t-strings →Templateオブジェクト - ⚡ 即時評価:f-strings → する / t-strings → する(ただし「結合」せず構造として保持)
- 🔒 セキュリティ:f-strings → 自分で気をつける必要あり / t-strings → コードで強制しやすい
- 🧩 対象:f-strings → 全ての人 / t-strings → 主にライブラリ作者・セキュリティ重視の実装
- 🔧 複雑さ:f-strings → シンプル / t-strings → レンダー関数が必要
まとめ:Python 3.14 の t-strings、どんな機能?
t-strings(テンプレート文字列)について調べたことをざっくりまとめてみました。
- t-strings は Python 3.14(PEP 750)で追加された新機能で、f-strings と似た親しみやすい構文を使いつつカスタム文字列処理を実現する
- f-strings と見た目は似ているが、返り値は
strではなくTemplateオブジェクト Templateは静的テキスト部分と補間部分(Interpolation)を分けて保持する- イテレートしながら補間値を加工できるので、XSS対策・ログマスキングなどに有効
- 日常のフォーマットは f-strings で十分。t-strings はセキュリティや柔軟な処理が必要な場面で使うもの
- 主にライブラリ作者や、セキュリティを意識した実装をしたい人向けの機能っぽいです
個人的には「f-strings の上位互換」ではなく「用途が違う別の道具」という認識がしっくりきました。とはいえまだ実務で使い倒せていないので、引き続き手を動かしながら理解を深めていきたいなと思っています。参考になれば!

