鈴木たかのり
t-stringとは
t-stringは、Python 3.
t-stringではf-stringの代わりに文字列のプレフィックスとしてtを指定します。t-stringの実行結果は文字列ではなく、新しいTemplateというデータ型になります。
>>> name = "takanory"
>>> tstr = t"こんにちは{name}!" # t-stringを定義
>>> type(tstr)
<class 'string.templatelib.Template'> # Templateオブジェクトを確認
>>> tstr # 結果を見やすくするために改行を入れている
Template(strings=('こんにちは', '!'),
interpolations=(Interpolation('takanory', 'name', None, ''),))
>>> fstr = f"こんにちは{name}!" # f-stringを定義
>>> type(fstr) # 文字列型
<class 'str'>
>>> fstr
'こんにちはtakanory!'
t-stringが追加された目的
f-stringと似ていますが異なるオブジェクトTemplate型を返すt-stringは、なぜ追加されたのでしょうか? その背景は、t-stringが言語仕様として提案されたPEP 750に書いてあります。
f-stringは変数などを含んだ文字列を作成するときに非常に便利に使われています。しかしf-stringでは{}の中の補完される値を、文字列の作成時に取得する方法がありません。そのため、不用意にf-stringを使用するとセキュリティ上の問題が発生する可能性があります。
たとえばSQLを作成するときやHTMLを作成するときにf-stringを安易に使用すると、SQLインジェクション[1]やクロスサイトスクリプティング
name = "takanory'; (悪意のあるSQL); --"
sql = f"SELECT * FROM users WHERE name = '{name}' # 悪意のあるSQLが実行される
name = "<script>(悪意のある処理)</script>"
html = f"<div>Name: {name}</div>" # 悪意のある処理が実行される
t-stringによって作成されるTemplate型では、固定の文字列と{}で補完される値にそれぞれアクセスする方法を提供することによって、このような問題に対処できます。
Template型の詳解
では、Template型がどういうデータ型かを見てみましょう。Template型は3つの属性を持っています。stringsとinterpolationsとvaluesです。それぞれ以下の情報が格納されています。
strings: 固定の文字列部分のタプル。型は文字列のタプルingterpolations:{}で記述された箇所を表すInterpolationsというオブジェクトのタプル。interpolationは「加筆、改ざん部分、補間」 といった意味があります values:interpolationsの挿入される値のタプル。型はobjectのタプル
Template型の3つの属性を確認します
>>> name = "takanory"
>>> tstr = t"こんにちは{name}!" # t-stringを定義
>>> type(tstr)
<class 'string.templatelib.Template'> # Template型
>>> tstr
Template(strings=('こんにちは', '!'),
interpolations=(Interpolation('takanory', 'name', None, ''),))
>>> tstr.strings
('こんにちは', '!')
>>> tstr.interpolations
(Interpolation('takanory', 'name', None, ''),)
>>> tstr.values
('takanory',)
これらの属性をもう少し詳しく見てみます。
{}の前後に固定の文字列が指定されていなくても、stringsには長さ0の文字列が挿入されます。つまり、stringsの数は必ずinterpolationsより1つ多くなります。また、interpolationsとvaluesの数は常に同じになります。
>>> name = "takanory"
>>> tstr2 = t"{name}"
>>> tstr2.strings # 固定の文字列がなくても空にはならない
('', '')
>>> tstr3 = t"{name}{name.upper()}"
>>> tstr3.strings # Interpolationの間にも必ず文字列が入る
('', '', '')
>>> tstr3.interpolations
(Interpolation('takanory', 'name', None, ''),
Interpolation('TAKANORY', 'name.upper()', None, ''))
>>> tstr4 = t"名前: {name}\n大文字の名前{name.upper()}"
>>> tstr4.strings
('名前: ', '\n大文字の名前', '')
>>> tstr4.interpolations
(Interpolation('takanory', 'name', None, ''),
Interpolation('TAKANORY', 'name.upper()', None, ''))
>>> tstr4.values
('takanory', 'TAKANORY')
続いてInterpolation型を見ていきます。
Interpolation型の詳解
Interpolation型は以下の4つの属性を持っています。
value: 補完される値。型はobjectexpression:{}の中に書かれた式。!、:、=が存在する場合はその直前までが格納される。型は文字列conversion: 値( value)に対して適用される変換。 !に続けて記述する。a、r、sまたはNoneformat_: 値spec ( value)に対して適用されるフォーマット指定。 :に続けて記述する。型は文字列
なお、Template型のvalues属性はtuple(i.と同じ意味になります。
Interpolation型の各属性を確認する前に、conversion、format_がどういうものかをf-stringで確認します。詳細については以下の公式ドキュメントを参照してください。
conversion、format_specの動作をf-stringで確認する>>> name = "たかのり"
>>> f"{name}" # conversion、format_specの指定なし
'たかのり'
>>> f"{name!r}" # !rを指定するとrepr()で変換される
"'たかのり'"
>>> f"{name!a}" # !aを指定するとascii()で変換される
"'\\u305f\\u304b\\u306e\\u308a'"
>>> num = 12.3456
>>> f"{num:2.2f}" # 表示桁数を指定
'12.35'
>>> count = 65536
>>> f"{count:#0x}" # 16進数で表示
'0x10000'
>>> today = date.today()
>>> f"{today:%Y年%m月%d日}" # 日付のフォーマットを指定
'2025年11月10日'
conversion、format_について確認したところで、Interpolationの値について確認します。それぞれ!、:の後ろに記述した内容が格納されていることが確認できます。
>>> name = "たかのり"
>>> inter = t"{name!r}".interpolations[0] # 最初のInterpolationを取得
>>> inter
Interpolation('たかのり', 'name', 'r', '')
>>> inter.value, inter.expression, inter.conversion, inter.format_spec # 属性を確認
('たかのり', 'name', 'r', '')
>>> num = 12.3456
>>> inter2 = t"{num * 2:2.2f}".interpolations[0]
>>> inter2.value, inter2.expression, inter2.conversion, inter2.format_spec
(24.6912, 'num * 2', None, '2.2f')
なお、t-stringではフォーマット処理は行わないため、format_にデータ型に対応しないフォーマットを指定してもエラーになりませんconversionはa、r、s以外を指定するとエラーになります。
conversion、format_specに適当な値を指定する>>> name = "たかのり"
>>> t"{name!f}" # conversionに正しくない文字を指定するとエラー
File "<python-input-65>", line 1
tstr = t"{name!f}"
^
SyntaxError: t-string: invalid conversion character 'f': expected 's', 'r', or 'a'
>>> f"{name:2.2f}" # f-stringでは対応しないformat_specを指定するとエラー
Traceback (most recent call last):
File "<python-input-66>", line 1, in <module>
f"{name:2.2f}"
^^^^^^^^^^^
ValueError: Unknown format code 'f' for object of type 'str'
>>> t"{name:2.2f}" # t-stringではエラーにならない
Template(strings=('', ''),
interpolations=(Interpolation('たかのり', 'name', None, '2.2f'),))
>>> t"{name:ほげほげ}" # 適当なformat_specも指定可能
Template(strings=('', ''),
interpolations=(Interpolation('たかのり', 'name', None, 'ほげほげ'),))
t-stringでセキュリティ問題に対応する
ここでは、例としてt-stringで記述されたSQLのテンプレートを処理するライブラリ、t-sqlを使います。t-sqlを使用すると、t-stringで定義したSQL文からSQLインジェクションに対処したSQL文の文字列を返します。
>>> import tsql
>>> name = "takanory'; (悪意のある処理); --"
>>> tstr_sql = t"SELECT * FROM users WHERE name = '{name}'" # t-stringでSQLを作成
>>> sql, values = tsql.render(tstr_sql) # tsqlでSQLを処理
>>> sql
"SELECT * FROM users WHERE name = '?'" # ?プレースホルダーを使用
>>> values
["takanory'; (悪意のあるSQL); --"]
>>> sql, _ = tsql.render(tstr_sql, style=tsql.styles.ESCAPED) # '文字をエスケープ
>>> sql
"SELECT * FROM users WHERE name = ''takanory''; (悪意のあるSQL); --''"
もう1つの例として、tdomでHTMLを処理します。tdomを使用すると、t-stringで定義したHTMLから、XSSに対応したHTMLの文字列を取得できます。
>>> import tdom
>>> name = "<script>(悪意のある処理)</script>"
>>> tstr_html = t"<div>Name: {name}</div>" # t-stringでHTMLを作成
>>> tdom_html = tdom.html(tstr_html) # tdomでHTMLを処理
>>> type(tdom_html) # 結果はElement型
<class 'tdom.nodes.Element'>
>>> print(tdom_html) # printするとエスケープされる
<div>Name: <script>(悪意のある処理)</script></div>
続いて、簡単なサンプルプログラムで実際にt-stringを処理してみます。
t-stringを処理するプログラムを作成する
ここではt-stringを処理して結果を返すプログラムを作成してみます。まずは単純に値を取り出してみます。実はTemplateオブジェクトはイテレーターに対応しており、固定の文字列とInterpolationを順番に取得できます。ただし、空の文字列は無視されます。
>>> name = "takanory"
>>> tstr = t"こんにちは{name}!"
>>> tstr # Templateオブジェクトを確認
Template(strings=('こんにちは', '!'),
interpolations=(Interpolation('takanory', 'name', None, ''),))
>>> list(tstr) # リストにすると固定の文字列とInterpolationのリストになる
['こんにちは', Interpolation('takanory', 'name', None, ''), '!']
>>> for item in tstr: # forループで順番に値を取得
... if isinstance(item, str):
... print(f"str: {item}") # 文字列
... else:
... print(f"Interpolation: {item}") # Interpolation
...
str: こんにちは
Interpolation: Interpolation('takanory', 'name', None, '')
str: !
>>> tstr2 = t"こんにちは{name}{name}"
>>> tstr2
Template(strings=('こんにちは', '', ''),
interpolations=(Interpolation('takanory', 'name', None, ''),
Interpolation('takanory', 'name', None, '')))
>>> list(tstr2) # リストにすると空文字列は出力されない
['こんにちは',
Interpolation('takanory', 'name', None, ''),
Interpolation('takanory', 'name', None, '')]
以下は、安全なHTMLを生成するプログラムの例です。Interpolationの値value)escape()関数を使用してエスケープします。
>>> from html import escape
>>> name = "<script>(悪意のある処理)</script>"
>>> tstr = t"<div>Name: {name}</div>" # t-stringでHTMLを作成
>>> parts = [] # 結果を格納する変数
>>> for item in tstr:
... if isinstance(item, str):
... parts.append(item)
... else:
... parts.append(escape(item.value)) # エスケープする
...
>>> "".join(parts) # 文字列にまとめる
'<div>Name: <script>(悪意のある処理)</script></div>'
Template型のその他の特徴
最後にTemplate型のその他の特徴を紹介します。
Template型はstr()で文字列に変換してもf-stringの結果のような文字列にはなりません。結果はTemplateオブジェクトの情報をそのまま含んだ文字列となり、repr()と同じ結果になります。
>>> name = "takanory"
>>> tstr = t"こんにちは{name}!"
>>> str(tstr) # Templateを文字列に変換
"Template(strings=('こんにちは', '!'), interpolations=(Interpolation('takanory', 'name', None, ''),))"
>>> repr(tstr) # str()とrepr()の結果は同じ
"Template(strings=('こんにちは', '!'), interpolations=(Interpolation('takanory', 'name', None, ''),))"
また、TemplateオブジェクトはTemplateオブジェクトとのみ連結が可能で、文字列との連結はできません。
>>> name = "takanory"
>>> tstr = t"こんにちは{name}!"
>>> drink = "beer"
>>> tstr2 = t"おいしい{drink}を楽しもう!"
>>> tstr + tstr2 # Templateを連結
Template(strings=('こんにちは', '!おいしい', 'を楽しもう!')
interpolations=(Interpolation('takanory', 'name', None, ''),
Interpolation('beer', 'drink', None, '')))
>>> tstr + drink # Templateと文字列の連結はエラーとなる
Traceback (most recent call last):
File "<python-input-30>", line 1, in <module>
tstr + drink
~~~~~^~~~~~~
TypeError: can only concatenate string.templatelib.Template (not "str") to string.templatelib.Template
t-stringではf-stringと同様に=が使用できます。t-stringの場合は{}の中に記述した式と同じ文字列が、stringsの中に挿入されます。
=の動作を確認>>> name = "takanory"
>>> f"こんにちは{name=}!" # 文字列にname=が挿入される
"こんにちはname='takanory'!"
>>> t"こんにちは{name=}!" # stringsにname=が挿入される
Template(strings=('こんにちはname=', '!'),
interpolations=(Interpolation('takanory', 'name', 'r', ''),))
>>> t"{1111*1111=}" # 式も記述できる
Template(strings=('1111*1111=', ''),
interpolations=(Interpolation(1234321, '1111*1111', 'r', ''),))
まとめ
Python 3.
現時点ではt-stringはリリースされたばかりで、大きな新機能ではありますが、対応するライブラリも少ないため
t-stringを考案した人たちも想像していないような、便利な面白い使い方が出てくるかもしれません。t-stringの周辺の状況にこれから注目していきたいと思います。
参考資料
- What's new in Python 3.
14 — Python 3. 14. 0 ドキュメント - string.
templatelib --- Support for template string literals — Python 3. 14. 0 ドキュメント - 2. 字句解析 — Python 3.
14. 0 ドキュメント - string --- 一般的な文字列操作 — Python 3.
14. 0 ドキュメント - PEP 750 – Template Strings | peps.
python. org - koxudaxi/
pyconjp_ 2025: Slides and assets for PyCon JP 2025
