
Python 3.15 の新機能 - lazy imports と UTF-8 デフォルト化で何が変わるか
Python らしい書き方を深く学べます。
実務で効く定石が詰まった一冊です。
言語仕様を体系的に押さえられます。
当サイトは Amazon.co.jp を宣伝しリンクすることで紹介料を得る手段を提供する、Amazonアソシエイト・プログラムの参加者です。価格・在庫はリンク先の最新情報をご確認ください。
Python の年次リリースが、また一つ大きな節目を迎えます。Python 3.15 には、長年議論されてきた明示的な lazy imports(PEP 810)と、UTF-8 のデフォルト化(PEP 686)という、実務への影響が大きい2つの変更が入ります。
この記事は 2026年9月22日時点の情報です。Python 3.15.0 はまだ正式リリースされていません。PEP 790 のスケジュールでは、最終版のリリース予定日は 2026年10月1日。現在は 2026年9月1日に公開された 3.15.0rc2(最後のリリース候補の予定)の段階です。以下は公式ドキュメント(3.15.0rc2 時点)と各 PEP を一次ソースに整理したもので、最終版で細部が変わる可能性がある点はご了承ください。
Python 3.15 の注目点(早見表)
| 項目 | 内容 |
|---|---|
| PEP 810 | 明示的な lazy imports。lazy import json で初回利用まで読み込みを遅延 |
| PEP 686 | UTF-8 がデフォルトエンコーディングに。ロケールに依存しなくなる |
| PEP 814 | 組み込み型 frozendict(イミュータブル・ハッシュ可能なマッピング) |
| PEP 661 | 組み込みの sentinel()。object() によるセンチネル自作から卒業 |
| PEP 798 | 内包表記でのアンパック([*L for L in lists]) |
| PEP 799 | profiling パッケージ新設。サンプリングプロファイラ Tachyon を同梱 |
| PEP 803 | free-threaded ビルド向け Stable ABI(abi3t) |
| PEP 831 | フレームポインタをデフォルトで有効化(観測性の向上) |
| リリース | 2026年10月1日予定(現在 3.15.0rc2)。サポートは 2031年10月まで |
リリース状況とサポート期限
まず現在地の確認です。手元の環境で確認すると、安定版はまだ 3.14 系です。
$ python3 --version
Python 3.14.7Python Developer's Guide のバージョン一覧によると、各バージョンの位置づけは次のとおりです。
| バージョン | ステータス | 初回リリース | サポート終了 |
|---|---|---|---|
| 3.16 | 開発中(main ブランチ) | 2027年10月6日予定 | - |
| 3.15 | プレリリース | 2026年10月1日予定 | 2031年10月 |
| 3.14 | バグフィックス | 2025年10月7日 | 2030年10月 |
| 3.13 | バグフィックス | 2024年10月7日 | 2029年10月 |
3.15.0rc2 のアナウンスでは、rc1 以降に76人のコントリビュータから約144件のバグ修正等が入ったこと、ここから先は ABI の変更がないため、サードパーティのライブラリ作者は 3.15 向け wheel の準備・公開を進めてほしい、という趣旨が述べられています。
NOTE
リリース候補の段階では「明確なバグ修正のみ」が取り込まれます。したがって本記事で扱う機能セット自体は、最終版でもほぼこのままになる見込みです。ただし細かな挙動やドキュメントの記述は変わり得るので、本番導入の判断は正式リリース後の What's New で再確認してください。
PEP 810: 明示的な lazy imports
3.15 の目玉が lazy imports です。lazy というソフトキーワードを import 文の前に置くと、その名前が初めて使われるまでモジュールのロードと実行が遅延されます。
lazy import json
lazy from pathlib import Path
print("Starting up...") # この時点では json も pathlib もロードされていない
data = json.loads('{"key": "value"}') # ここで json が実際にロードされる
p = Path(".") # ここで pathlib が実際にロードされる期待される出力は次のようになります。起動時のログが先に出て、重いモジュールのロードは後回しになる、というのが体感できるポイントです。
Starting up...何が嬉しいのか
狙いは起動時間・メモリ使用量の削減です。特に CLI ツールでは「サブコマンドごとに必要なライブラリが違うのに、起動時に全部 import している」という構造が非常によくあります。PEP 810 では、実運用での導入事例としてCLI ツールで起動時間が50〜70%削減したという報告が挙げられています。
NOTE
数値は PEP 810 に記載された報告値であり、あらゆるアプリで再現するものではありません。効果は「起動時に何をどれだけ import しているか」に完全に依存します。自分のプロジェクトで測る場合は python -X importtime が手軽です。
書ける場所・書けない場所
lazy はどこにでも書けるわけではありません。公式ドキュメントに明記された制約は以下です。
- モジュールスコープ限定。関数の中、クラス本体、
try/except/finallyブロックの中で使うとSyntaxError - スター import は不可。
lazy from module import *はSyntaxError - future import は不可。
lazy from __future__ import ...もSyntaxError
def main():
lazy import json # SyntaxError: 関数スコープでは使えません
try:
lazy import numpy # SyntaxError: try ブロック内では使えません
except ImportError:
numpy = Noneソースを書き換えずに有効化する
既存コードに手を入れずに遅延ロードを試したいケース向けに、3つの入口が用意されています。
| 手段 | 指定方法 |
|---|---|
| コマンドラインオプション | -X lazy_imports=all |
| 環境変数 | PYTHON_LAZY_IMPORTS=all |
| 実行時 API | sys.set_lazy_imports() / sys.get_lazy_imports() |
-X lazy_imports と PYTHON_LAZY_IMPORTS が取る値は2つです。all はすべての import をデフォルトで lazy にする、normal(既定値)はソース中の lazy キーワードだけを尊重する、という違いです。
さらに、モジュール単位で細かく制御したい場合は sys.set_lazy_imports_filter() にコールバックを渡せます。フィルタは「import 元のモジュール名(または None)」「import されるモジュール名」「fromlist(通常の import では None)」の3引数を受け取り、True を返せば遅延、False を返せば即時ロードになります。
古い Python と両立させる __lazy_modules__
lazy キーワードは 3.15 で追加された構文なので、それより前のバージョンでは構文エラーになります。3.14 以前もサポートしつつ 3.15 では遅延させたい、というライブラリ向けに、モジュール変数 __lazy_modules__ が用意されています。
__lazy_modules__ = ["json", "pathlib"]
import json # lazy として扱われる
import os # こちらは従来どおり即時ロード完全修飾のモジュール名を並べておくと、通常の import 文が lazy キーワードと同じセマンティクスで扱われます。この書き方なら 3.15 未満の Python でも単なる文字列リストとして無視されるだけなので、構文エラーになりません。
注意点: 失敗のタイミングがずれる
遅延ロードの最大の落とし穴は、ImportError が import 文の行ではなく「名前を初めて使った行」で発生することです。起動直後に落ちてくれていたものが、リクエスト処理の途中やバッチの終盤で落ちるようになり得ます。
PEP 810 では例外チェーンを使った報告の強化(どこで lazy import が宣言され、どこで失敗したかを両方示す)が言及されていますが、失敗が後ろにずれるという性質そのものは変わりません。サーバアプリで -X lazy_imports=all を無条件に有効化するのは避け、まずは CLI や起動の速さが効く場所から、明示的な lazy キーワードで局所的に導入するのが安全です。
WARNING
副作用を持つモジュール(import 時にプラグイン登録やモニタリングの初期化を行うもの)を lazy にすると、その副作用が「いつ起きるか分からない」状態になります。import 時の副作用に依存している箇所は lazy 化の対象から外してください。
PEP 686: UTF-8 がデフォルトエンコーディングに
もう一つの大きな変更が、UTF-8 のデフォルト化です。公式ドキュメントは次のように説明しています。Python はシステム環境から独立して UTF-8 を既定のエンコーディングとして使うようになり、open('flying-circus.txt') のように encoding を省略した I/O は UTF-8 になります。
これまで open() の既定エンコーディングはロケール依存で、日本語の Windows 環境では CP932(Shift_JIS 系)になっていました。「Mac では動くのに Windows で UnicodeDecodeError」という古典的なトラブルの主因がこれです。3.15 ではその前提が変わります。
# 3.14 以前: ロケール依存(日本語 Windows では CP932 など)
# 3.15 以降: 常に UTF-8
with open("memo.txt") as f:
text = f.read()影響と回避策
公式ドキュメントが挙げているポイントを整理します。
- 適用されるのは
encoding引数を渡していない場合だけです。バージョン間の互換性を最大化したいなら、常に明示的にencodingを渡すのが最善です - 影響を受ける箇所の洗い出しには、オプトインのエンコーディング警告(
EncodingWarning)が使えます - ロケールのエンコーディングを使いたい場合は、Python 3.10 からサポートされている
encoding='locale'を明示します - 従来の挙動に戻したい場合は、環境変数
PYTHONUTF8=0かコマンドラインオプション-X utf8=0で UTF-8 モードを無効化できます
また PEP 686 には、ロケールのエンコーディングを UTF-8 モードの影響を受けずに取得する locale.getencoding() の追加も含まれます。
移行の進め方
PEP 686 が推奨する手順は「UTF-8 モードを一時的に無効化する」「EncodingWarning でエンコーディングに依存している箇所を洗い出す」「UTF-8 モードを有効にしてテストする」の3ステップです。実際には、3.14 以前の段階でも次のように警告を出して事前に棚卸しできます。
$ python3 -X warn_default_encoding -W error::EncodingWarning your_script.pyencoding を省略した open() や locale.getpreferredencoding() の呼び出しがあれば、そこで例外として浮かび上がります。CI に組み込んでおくと、3.15 に上げる前に差分を潰せます。
WARNING
逆方向のリスクもあります。CP932 で書かれたレガシーな CSV やログを「ロケール任せ」で読んでいたコードは、3.15 では UTF-8 として解釈され UnicodeDecodeError になります。読み込み側に encoding='cp932' を明示するのが正攻法です。文字コードそのものの前提知識は文字コード入門 - UTF-8 と Unicode の仕組みにまとめてあります。
組み込み型が2つ増える: frozendict と sentinel
PEP 814: frozendict
イミュータブルでハッシュ可能なマッピングが組み込み型として追加されます。
>>> a = frozendict(x=1, y=2)
>>> hash(a)
3527539
>>> {a: "config"} # 辞書のキーにできる
{frozendict({'x': 1, 'y': 2}): 'config'}ポイントは以下です。
collections.abc.Mappingプロトコルを実装し、挿入順を保持します- キーはハッシュ可能である必要があり、値がハッシュ可能なら frozendict 自体もハッシュ可能になります。ハッシュ値は要素の順序に依存しません
- ハッシュ可能なので、辞書のキー・集合の要素・
@functools.lru_cache()を付けた関数の引数に使えます - マージ演算子
|と|=を dict との間でサポートします dictのサブクラスにはしない方針が採られました。継承を許すとイミュータビリティを迂回でき、dict本体の性能にも影響しうるためです
既存の types.MappingProxyType(3.3 で追加)との違いも PEP に整理されています。MappingProxyType はハッシュ不可で、継承もできず、元の辞書を取り出して書き換えることも容易でした。frozendict はその弱点を埋めるものです。
PEP 661: sentinel
「値が渡されなかったこと」を表すために _MISSING = object() と書くのは、Python の定番イディオムでした。3.15 では組み込みの sentinel() が使えます。
MISSING = sentinel('MISSING')
def foo(value=MISSING):
if value is MISSING:
...sentinel() は位置専用引数の name(文字列)を取り、オプションで repr キーワード引数を受け付けます。object() では <object object at 0x000002825DF09650> のような読みにくい repr になっていたところが、次のように簡潔になります。
>>> MISSING = sentinel('MISSING')
>>> MISSING
MISSINGPEP 798: 内包表記でのアンパック
内包表記とジェネレータ式の中で * と ** によるアンパックが書けるようになります。
>>> lists = [[1, 2], [3, 4], [5]]
>>> [*L for L in lists]
[1, 2, 3, 4, 5]
>>> dicts = [{'a': 1}, {'b': 2}]
>>> {**d for d in dicts}
{'a': 1, 'b': 2}これまで itertools.chain.from_iterable() や二重ループで書いていた「平坦化」が、1行で素直に表現できます。
PEP 799: profiling パッケージと Tachyon
プロファイリング関連が profiling パッケージに整理され、2つのサブモジュールが提供されます。
profiling.tracing: 決定的な関数呼び出しトレースprofiling.sampling: 統計的サンプリングプロファイラ Tachyon
Tachyon は最大 1,000,000 Hz という高頻度のサンプリングに対応し、壁時計時間・CPU・GIL 保持・例外といった複数のモードと、pstats / フレームグラフ / Firefox Profiler / ヒートマップといった出力形式を持ちます。async 対応のプロファイリングも可能です。
あわせて、従来の profile モジュールは非推奨となり、Python 3.17 で削除される予定です。
また PEP 831 により、CPython は フレームポインタを有効(-fno-omit-frame-pointer)にしてビルドされるようになります。perf などシステムレベルのプロファイラからスタックが正しく追えるようになる、という観測性の改善です。
free-threading の現在地
3.13 で実験的に導入され(PEP 703)、3.14 で「公式にサポートされる」段階に進んだ(PEP 779)free-threaded ビルドは、3.15 ではエコシステム側の整備が主題になります。
PEP 803 により、Stable ABI をターゲットにする C 拡張が free-threaded ビルド向け Stable ABI(abi3t) 向けにコンパイルできるようになりました。ただし abi3t を使うには、PEP 697 で導入された API(負の basicsize や PyObject_GetTypeData() など)への移行と、PyInit_ 関数から PEP 793 の新しいエクスポートフック PyModExport_* への切り替えが必要です。
公式ドキュメントは、Stable ABI が CPython の全機能を提供するわけではない点にも触れており、abi3t に移行できない拡張は従来どおり abi3 と free-threading 向けのバージョン固有 ABI(cp315t)を別々にビルドし続けることになります。
NOTE
free-threaded ビルドは 3.15 でもデフォルトのビルドではありません。通常の配布物は GIL ありのビルドで、free-threading を使うには専用ビルドを選ぶ必要があります。「3.15 で GIL が無くなる」ではない点に注意してください。
型システムとエラーメッセージ
型まわりでは3つの PEP が入ります。
- PEP 728:
TypedDictに「型付きの追加項目」を許す - PEP 747:
TypeForm(型そのものを値として注釈する) - PEP 800: 型システムにおける互いに素な基底クラス(disjoint bases)
エラーメッセージの改善も継続しています。AttributeError の候補提示が改善され(他言語のメソッド名からの推測を含む)、delattr() の失敗時にも候補が出るようになりました。また対話シェル(PyREPL)では、補完候補がオブジェクトの種類に応じて色分けされ、from ... import でのモジュール属性の補完も効くようになります。argparse・ast・calendar・sqlite3・timeit など CLI の出力にも色が増えました。
削除・非推奨
移行時に確認しておきたい変更です。
__cached__モジュール属性の削除: 3.13 で非推奨だったもので、import システムも標準ライブラリもこれを設定・参照しなくなりました。代わりに__spec__.cachedを使いますprofileモジュールの非推奨: 3.17 で削除予定。profiling.tracingへ移行しますre.match()/re.Pattern.match()のソフト非推奨: 名前が紛らわしいため、明示的なre.prefixmatch()/re.Pattern.prefixmatch()が導入されました。削除の予定はありませんPyGILState系 C API のソフト非推奨:PyGILState_Ensure()/PyGILState_Release()などは削除予定こそないものの、今後新しいPyGILStateAPI が追加されることはありません
このほか ast・ctypes・datetime・glob・http.server・importlib・pathlib・platform・sysconfig・threading・typing・wave などに、以前から非推奨だった API の削除が入っています。詳細な一覧は What's New in Python 3.15 の Removed セクションを参照してください。
NOTE
標準ライブラリの細かな削除項目については、本記事では個別の網羅までは確認できていません(要確認)。実際の移行時は -W error::DeprecationWarning を付けて 3.14 でテストを回し、警告を潰してから 3.15 に上げるのが確実です。
3.14 からの流れ
3.15 単体では分かりにくい変化も、直前の 3.14 と並べると方向性が見えます。3.14 では、アノテーションの遅延評価(PEP 649 / PEP 749)、標準ライブラリでの複数インタプリタ(PEP 734)、テンプレート文字列リテラル(t-string, PEP 750)、Zstandard 対応(PEP 784)、そして free-threaded Python の公式サポート(PEP 779)が入りました。
つまり 3.14 が「言語・実行モデルの拡張」だったのに対し、3.15 は lazy imports で起動を速くし、UTF-8 デフォルト化で環境差を消し、profiling パッケージとフレームポインタで計測しやすくするという、実行環境の整備に寄った版だと言えます。
なお 3.15 の What's New に t-string(PEP 750)関連の新セクションは見当たりませんでした。3.14 で入った機能がそのまま継続する形です。
移行チェックリスト
正式リリース後に 3.15 を試すなら、次の順で確認するとスムーズです。
- 3.14 で
DeprecationWarningを潰す:python -W error::DeprecationWarning -m pytestでテストを回す - エンコーディング依存を洗い出す:
python -X warn_default_encoding -W error::EncodingWarningでencoding未指定の I/O を特定し、明示的に指定する - CP932 等を読むコードに
encodingを明示する: UTF-8 デフォルト化で壊れる典型パターン __cached__の参照を検索する:grep -rn "__cached__"して__spec__.cachedに置き換えるprofileモジュールの利用箇所を確認する:profiling.tracingへの移行計画を立てる- lazy imports は起動時間を測ってから:
python -X importtimeでボトルネックの import を特定し、効果が見込める箇所に絞ってlazyを付ける - 依存ライブラリの 3.15 対応 wheel を確認する: rc2 以降 ABI 変更はないため、PyPI 上の cp315 wheel の有無が判断材料になります
バージョン管理そのものを整理したい場合は、pyenv から uv への移行も合わせて検討する価値があります。uv なら uv python install 3.15 のような形で 3.15 を隔離した環境に入れて試せます。データ分析まわりで試すなら、Jupyter Notebook 徹底解説で触れているカーネルの切り替えも使えます。
まとめ
- Python 3.15 は 2026年10月1日リリース予定。2026年9月22日時点では 3.15.0rc2 の段階で、まだ正式リリースされていません
- PEP 810 の lazy imports は起動時間の削減に効きますが、
ImportErrorの発生タイミングが後ろにずれるという性質があります。CLI から局所的に導入するのが安全です - PEP 686 の UTF-8 デフォルト化は、Windows の CP932 問題を根本から解消する一方、CP932 を前提にしていたコードを壊します。
encodingの明示が最善の備えです frozendict・sentinelという定番イディオムの言語化、内包表記でのアンパック、profilingパッケージなど、地味に効く改善も揃っています- free-threading は 3.15 でもデフォルトではありません。3.15 の主題は
abi3tによるエコシステム側の整備です
参考リンク
- What's New In Python 3.15 - Python 3.15.0rc2 documentation
- PEP 790 - Python 3.15 Release Schedule
- PEP 810 - Explicit lazy imports
- PEP 686 - Make UTF-8 mode default
- PEP 814 - Add frozendict builtin type
- PEP 661 - Sentinel values
- PEP 803 - Stable ABI for Free-Threaded Builds
- Python 3.15.0 candidate 2 is here! - Python Insider
- Status of Python versions - Python Developer's Guide
- What's New In Python 3.14


