Python 3.14 の新機能整理 — t-string、遅延アノテーション、フリースレッディング公式サポート

読了 6分

Python 3.14 は 2025 年 10 月にリリースされました。円周率バージョン(3.14)というジョークとともに登場しましたが、中身はずっしりしています。新しい文字列構文がひとつ、長年引きずってきたアノテーション問題の結論、そして Python の並行処理の方向を変えるフリースレッディングの公式化まで。この記事では実務への影響が大きい順に 3.14 の変化を整理します。

t-string — f-string に似ていますが文字列ではありません(PEP 750) #

いちばん目を引く新構文です。f の代わりに t を付けると、即座に文字列になる代わりに Template オブジェクトが作られます。

t_string.py
name = "世界"

greeting_f = f"こんにちは、{name}"   # str: "こんにちは、世界"
greeting_t = t"こんにちは、{name}"   # Template オブジェクト: まだ文字列ではない

# Template には静的テキストと補間値が分離されたまま入っています
for part in greeting_t:
    print(repr(part))
# 'こんにちは、'
# Interpolation(value='世界', expression='name', ...)

核心は、消費する側が補間値をどう処理するかを決められるという点です。f-string は値が即座に文字列に溶け込んでしまうため、HTML エスケープや SQL バインドの処理を差し込む余地がありませんでした。t-string は値が分離されたまま渡されるので、ライブラリが値だけを選んでエスケープしたり、パラメータに変換したりできます。

safe_html.py
def safe_html(template) -> str:
    parts = []
    for item in template:
        if isinstance(item, str):
            parts.append(item)          # 静的テキストはそのまま
        else:
            parts.append(escape(str(item.value)))  # 補間値だけエスケープ
    return "".join(parts)

user_input = "<script>alert('x')</script>"
print(safe_html(t"<p>{user_input}</p>"))
# <p>&lt;script&gt;alert(&#x27;x&#x27;)&lt;/script&gt;</p>

f-string インジェクション問題の構造的な解法なので、HTML テンプレート、SQL、ログのマスキング、プロンプト組み立てのライブラリがこの上で作り直されつつあります。アプリケーションコードで t-string を直接書く機会は当面少ないですが、ライブラリが t-string を受け取り始めれば、「ユーザー入力が混ざる文字列は t-string で」が新しい慣行になる可能性が高いです。

アノテーションの遅延評価がデフォルトになります(PEP 649/749) #

これまで型ヒントは関数定義の時点で即座に評価されていました。そのため、まだ定義されていないクラスを参照すると NameError になり、回避のために文字列で包む("User")か、ファイルの先頭に from __future__ import annotations を置く慣行が広まっていました。

3.14 からは、アノテーションは必要になったときに評価されるのがデフォルト動作です。

annotations_demo.py
class Node:
    # 3.13 まで: NameError、または文字列 "Node" が必要
    # 3.14 から: そのまま動く
    def next_node(self) -> Node | None: ...
  • 循環参照のためにアノテーションを文字列で包んでいたコードは、もうその必要がありません。
  • from __future__ import annotations は今も動きますが、新しいコードでは不要になりました。
  • 実行時にアノテーションを読むコード(Pydantic、FastAPI のようなライブラリ)は、新設の annotationlib モジュール経由に標準化されました。主要ライブラリはすでに対応済みなので、アプリケーション開発者としては依存関係を最新にしておけば十分です。

フリースレッディング(GIL 除去)ビルドが公式サポートに(PEP 779) #

3.13 で実験的に入った free-threaded ビルドが、3.14 で実験扱いを卒業して公式サポート段階になりました。GIL(グローバルインタープリターロック)のない Python では、複数のスレッドが実際に複数のコアで同時に Python コードを実行します。

現実的な立ち位置を正確に知っておく必要があります。

  • 依然として別ビルドです(python3.14t)。デフォルトでインストールされる Python は GIL ありのままで、2 つのビルドは C 拡張の互換性が異なります。
  • シングルスレッド性能は GIL ビルドよりやや遅いです。差は 3.13 比で大きく縮まりましたがゼロではありません。
  • C 拡張のエコシステム(NumPy などの主要パッケージ)がフリースレッディング対応の wheel を出している途中で、その対応状況が導入の可否を決めます。

現時点の判断はこう要約できます。CPU 並列が切実なワークロードはフリースレッディングビルドを検証する価値が十分にあり、普通の Web サービスは急ぐ理由がありません。 Web アプリの並列性は今もプロセス(ワーカー)単位が標準です。プロセスとスレッドの違いがあいまいならプロセスとスレッドの違いを併せてどうぞ。

同じ文脈の変化として、マルチインタープリターが標準ライブラリに入りました(PEP 734、concurrent.interpreters)。ひとつのプロセスの中に GIL を各自持つインタープリターを複数立てる方式で、プロセスより軽く、スレッドより隔離された中間地点です。concurrent.futures.InterpreterPoolExecutor で従来の Executor インターフェースのまま使えます。

小さいけれどうれしい変化 #

  • 括弧なしの except(PEP 758): 複数の例外を捕まえるとき、except (ValueError, TypeError): の代わりに except ValueError, TypeError: と書けます。as を使うときは今も括弧が必要です。
  • Zstandard 圧縮の標準搭載(PEP 784): compression.zstd モジュールが入りました。gzip より速くてよく縮む zstd をサードパーティなしで使えます。
  • リモートデバッグインターフェース(PEP 768): 実行中の Python プロセスに外から安全に接続できる公式の経路ができ、pdb が対応しています。「本番で止められないプロセスの中を見たい」への標準回答ができたわけです。プロファイリング観点の同じ問題は py-spy で扱ったことがあります。
  • エラーメッセージの改善: タイプミスしたキーワード引数の提案、文字列と数値を誤って混ぜたときの案内などがより具体的になりました。バージョンを上げるだけでデバッグ体験が良くなる部分です。
  • UUID v6・v7・v8 対応: uuid モジュールが最新仕様に対応しました。特に時系列でソートできる UUIDv7 は、DB の主キー用途で需要の大きかった機能です。

アップグレードの判断 #

3.14 は構文の非互換変更がほとんどないリリースなので、アップグレードの障壁は低めです。手順はいつも同じです。依存ライブラリの 3.14 対応 wheel の存在を確認し、CI に 3.14 を追加してテストを通し、それからランタイムを上げます。uv を使っているなら uv python install 3.14 でバージョンを取得し、lock ファイルの再生成で検証する流れになります。複数バージョンの管理方法は Python パッケージング #4 で扱いました。

まとめ #

  • t-string は補間値が分離されたテンプレートオブジェクトを作り、エスケープとバインドをライブラリが処理できるようにします。インジェクション問題の構造的な解法です。
  • アノテーションの遅延評価がデフォルトになり、文字列で包む慣行と from __future__ import annotations が不要になりました。
  • フリースレッディングビルドが公式サポートになりました。CPU 並列のワークロードは検証の価値があり、普通の Web サービスは今もプロセス並列が標準です。
  • マルチインタープリター、zstd 圧縮、リモートデバッグ、UUIDv7 など、標準ライブラリの実務ツールが厚くなりました。
  • 非互換変更の少ないリリースなので、依存 wheel の確認 → CI 追加 → ランタイム更新の順で上げれば大丈夫です。
X