PEP 750 – テンプレート文字列(t-strings)が承認
(peps.python.org)- PEP 750 は Python に新しい文字列リテラルである テンプレート文字列(
t"...") を導入する - f-string を一般化した形で、
Template型を生成し、文字列と補間値を結合する前に処理できる機能を提供する - Web テンプレート、セキュリティ検査、DSL(Domain-Specific Language)などで有用に使える
他の PEP との関係
- f-string は PEP 498 で導入され、PEP 701 で構文が拡張された
- PEP 501 は汎用テンプレート文字列(
i-string)を提案したが保留となった - 現在の PEP 750 は PEP 501 を単純化・一般化した形で、既存のアイデアを基に発展したもの
動機と必要性
- f-string は簡単だが、補間値を事前に加工できないため、セキュリティ上の問題が発生する可能性がある
- SQL インジェクションや XSS 攻撃などの脆弱性を招くおそれがある
- テンプレート文字列を使うと、補間値を事前に加工して安全に利用できる
例:
evil = "<script>alert('evil')</script>"template = t"<p>{evil}</p>"assert html(template) == "<p><script>alert('evil')</script></p>"
テンプレート文字列の仕様
テンプレート文字列リテラル
- 接頭辞
tまたはTを使って定義する string.templatelib.Template型として評価される- f-string に似た構文をサポートし、ネストも可能
r接頭辞と組み合わせ可能(rt,tr)u,b接頭辞とは組み合わせ不可- f-string とテンプレート文字列は混在して使用できない
Template 型
- 不変型であり、次の属性を持つ:
strings: 文字列断片のタプルinterpolations: 補間値オブジェクトのタプルvalues: 補間値そのものの値タプル__iter__(): 文字列と補間値を順に返すイテレータ
Interpolation 型
value: 評価結果expression: 元の補間式文字列conversion: 変換方式(r,s,aまたは None)format_spec: 書式文字列
例:
name = "World"template = t"Hello {name!r}"assert template.interpolations[0].conversion == "r"
デバッグ指定子 =
t"{value=}"はt"value={value!r}"として解釈される- 空白もそのまま保持される(
t"{value = }"→"value = {value!r}")
テンプレート文字列の連結
+演算子でTemplateとstr、またはTemplate同士を結合できる- 連結結果は常に
Template型 - 暗黙的な文字列連結(
t"Hello " t"World")も可能
テンプレート文字列の処理方法
例: 大文字・小文字処理関数
def lower_upper(template):parts = []for s in template:if isinstance(s, str): parts.append(s.lower())else: parts.append(str(s.value).upper())
return "".join(parts)
例: f-string と同じ処理の実装
f()関数で f-string と同じ結果を生成できる
例: 構造化ロギング
- テンプレート文字列を使うと、ログメッセージと構造化された値を同時に出力できる
StructuredMessageまたはlogging.Formatterのサブクラスとして実装できる
例: HTML テンプレート処理
html()関数は補間位置に応じて内容を適切に escape したり属性として処理したりする- ネストしたテンプレートもサポートする
高度な使用パターン
- 構造的パターンマッチングの使用を推奨(
match文) - 静的文字列はキャッシュキーとして使え、効率的なメモ化が可能
- AST などの中間表現にパースして処理できる
- Lazy または Async 評価のために
lambda,awaitを使える
テンプレート文字列と既存のフォーマット文字列の関係
- 既存の
.format()に近い形でテンプレート関数を定義できる - 外部文字列をパースして
Templateに変換するfrom_format()も可能
互換性、セキュリティ、学習
- 旧バージョンの Python では構文エラーになる可能性がある
- セキュリティ面ではテンプレート処理が安全性を高める
- f-string に似た構文のため学習しやすい
なぜ新しいテンプレート方式なのか?
- 既存の Jinja のようなテンプレートはユーザー定義向け、またはデザイナー向け
- テンプレートを開発者が直接扱えるように、Python 言語レベルでのサポートが必要
- 表現力や型チェックなどの利点を活用できる
例示パターンの整理
- 構造的パターンマッチングと下位属性のマッチング
- テンプレートを関数のように再利用
- ネストしたテンプレートをサポート
- Lazy/Async 評価をサポート
- 静的/動的分離によるキャッシュ最適化
その他の設計上の考慮事項
- テンプレートは文字列に変換されず、
__str__()は未実装 string.templatelibモジュールで関連クラスを提供するTemplate,Interpolationはオブジェクト同一性基準で比較される==または<演算はサポートしない
参照実装と例
- CPython 実装
- 例とテスト を提供
却下されたアイデア
- 任意の接頭辞の使用(
my_tag"...") - すべての補間式の遅延評価
- プロトコルとして実装
__eq__,__hash__の再定義- 元の文字列の完全復元
Decoded型の追加- バイナリテンプレート文字列のサポート
- フォーマット種別("html", "sql" など)指定機能
- 文字列連結の制限
- 任意の変換子(
!x)の許可
3件のコメント
一番満足できるフォーマットは JS と Python くらいですね。他の言語はちょっと…。
明確で、できればただ一つの明白な方法があるべきだ。(There should be one-- and preferably only one --obvious way to do it.)
Hacker Newsのコメント
さまざまな言語が文字列フォーマットをどう扱うかは興味深い
.format()、f-strings、t-strings を通じて価値を得ているNick Humrich は PEP 501 を書き直して t-strings を導入した著者の一人であり、この PEP が受け入れられたことをとても喜んでいる
言語レベルの機能が価値あるものか確信できない
f-strings は好きだが、評価を遅延できない問題がある
str.formatを使わなければならない場合があり、不便だlit-html のメンテナとして、JavaScript のタグ付きテンプレートリテラルとの類似点が興味深い
Templateクラスが JavaScript のタグ関数と引数を分離するやり方は独特だhtml()関数が不要かもしれないJavaScript のタグ付きテンプレートリテラルが HTML の自動エスケープや SQL のパラメータ化に役立つ点が、Python にも適用されそうで期待している
Python が PHP に変わっていくようだという意見
string.formatが最適だと思っており、%も長く使われてきたのだから許容できる言語に新しいものを追加し続けることへの不満
この PEP は C++ の P1819 に似ているという意見
PEP のコードがあまりにも冗長だという意見