Python 3.15 新機能詳解:明示的な遅延インポートと組み込み frozendict がもたらす性能革新

Python · Release 3.15

Python 3.15 新機能詳解:明示的な遅延インポートと組み込み frozendict がもたらす性能革新

pythonPythonリリース遅延インポートfrozendictパフォーマンス最適化

データソース:GitHub Releases + 官方博客 + HN

Python 3.15 が 2026 年 10 月 9 日に正式リリースされました。今回のアップデートは、言語機能とパフォーマンス最適化の双方において数多くの進化をもたらしています。なかでも明示的な遅延インポート(lazy imports)は大規模アプリケーションにおける起動遅延のボトルネックを解消し、組み込み型 frozendict の追加によって待望のイミュータブルなマッピングが実現しました。さらに内包表記でのアンパックによるコードの簡潔化や、フリーレッド(free-threaded)ビルド向けの安定 ABI の導入により、Python は本格的なマルチスレッド時代へとさらに前進しています。本記事では、今回のリリースにおける最重要機能を詳しく解説します。

PEP 810: 明示的な遅延インポート(Explicit lazy imports)

大規模な Python アプリケーションでは、モジュールのインポートが連鎖することによる起動時間の遅さが長年の課題でした。従来は関数内部で遅延インポートを行ったり、importlib を用いてオンデマンドで読み込んだりする回避策が取られてきました。Python 3.15 では、より洗練された解決策として lazy ソフトキーワードによる明示的な遅延インポートが提供されます。

lazy import を使用すると、Python はモジュールを即座にはロードせず、軽量なプロキシオブジェクトを作成します。そして、そのモジュール内の属性や名前が初めてアクセスされた時点で初めて実際のロードを実行します。

lazy import json
lazy from pathlib import Path

print("Starting up...")  # json と pathlib はまだ完全にはインポートされていない

data = json.loads('{"key": "value"}')  # 初回アクセス時に初めて json が完全にインポートされる
p = Path(".")  # 初回アクセス時に初めて pathlib が完全にインポートされる

遅延インポート対象のモジュールが存在しない場合、例外は初回アクセス時に送出されます。また、環境変数 PYTHON_LAZY_IMPORTS やコマンドライン引数 -X lazy_imports を使用して、遅延インポートの挙動をグローバルに制御することも可能です。

PEP 814: 新たな組み込み型 frozendict の追加

Python 3.15 では、新しい不変(immutable)な組み込み型 frozendict が導入されました。これは dict のサブクラスではなく、object を直接継承しています。キーと値のすべてがハッシュ可能(hashable)である限り、frozendict 自体もハッシュ可能です。frozendict は挿入順序を保持しますが、等価性の比較(==)においては順序は考慮されません。

frozendict の登場により、不変なマッピングが必要な場面(辞書のキーやセットの要素など)の扱いが大幅に容易になります。

>>> a = frozendict(x=1, y=2)
>>> a
frozendict({'x': 1, 'y': 2})
>>> a['z'] = 3
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    a['z'] = 3
    ~^^^^^
TypeError: 'frozendict' object does not support item assignment
>>> b = frozendict(y=2, x=1)
>>> hash(a) == hash(b)
True
>>> a == b
True

PEP 798: 内包表記でのアンパック(Unpacking in comprehensions)

リスト、セット、辞書の内包表記、およびジェネレータ式において、* および ** を用いたアンパックがサポートされました。これは PEP 448 で導入されたアンパック構文の自然な拡張であり、複数のイテラブルや辞書を単一のフラットな構造へ統合する処理が極めてシンプルになります。ネストした内包表記や itertools.chain() の代替として直感的に記述できます。

>>> lists = [[1, 2], [3, 4], [5]]
>>> [*L for L in lists]  # [x for L in lists for x in L] と同等
[1, 2, 3, 4, 5]

>>> sets = [{1, 2}, {2, 3}, {3, 4}]
>>> {*s for s in sets}  # {x for s in sets for x in s} と同等
{1, 2, 3, 4}

>>> dicts = [{'a': 1}, {'b': 2}, {'a': 3}]
>>> {**d for d in dicts}  # {k: v for d in dicts for k,v in d.items()} と同等
{'a': 3, 'b': 2}

ジェネレータ式でも同様に記述可能です:

>>> gen = (*L for L in lists)  # (x for L in lists for x in L) と同等
>>> list(gen)
[1, 2, 3, 4, 5]

PEP 661: 新たな組み込み型 sentinel の追加

Python 3.15 では builtins モジュールに sentinel 型が追加され、明瞭な表現を持つ一意の番兵値(sentinel values)を標準的に作成できるようになりました。sentinel オブジェクトは浅いコピーを行っても同一性が保持され、型ヒント式における | 演算子に対応し、モジュールと名前経由でインポート可能な場合は pickle によるシリアライズもサポートされます。

PEP 803: フリーレッドビルド向け安定 ABI(abi3t)

フリーレッド(free-threaded)Python ビルド向けに、C 拡張モジュールがコンパイル時に利用できる新しい安定 ABI(abi3t)が導入されました。abi3t への対応には、PEP 697 で定義された API への移行や、PEP 793 で導入された新しいエクスポートフック PyModExport_* の利用など、ソースコードの修正が必要です。

直ちに abi3t へ移行できない拡張機能については、従来の安定 ABI(abi3)とバージョン固有のフリーレッド ABI(cp315t)の双方に向けて個別にビルドを継続する必要があります。

アップグレードの推奨事項と注意点

検討項目詳細内容
誰がアップグレードすべきか起動速度の改善が求められる大規模アプリケーションの開発者、辞書の頻繁なマージ操作を扱う開発者、フリーレッド(free-threaded)対応を進める C 拡張ライブラリのメンテナー。
いつアップグレードすべきかローカル開発環境やテスト環境では直ちに Python 3.15 の検証を開始できます。本番環境への導入は、依存ライブラリ(特に C 拡張を含むもの)が abi3t または cp315t に対応するのを待ってから移行することを推奨します。
注意点• cProfile のトレース機能は新設された profiling モジュールへと統合されました(PEP 799)。
• 従来の profile モジュールは非推奨となり、Python 3.17 で削除される予定です。
• .pth ファイル内での import 行がサイレントに非推奨となり、新しい .start 設定ファイルへの移行が推奨されます(PEP 829)。
• PyGILState 系 API はソフト非推奨となり、今後新たな同種 API は追加されません(PEP 788)。

参考リンク