2026年10月9日に公開されたPython 3.15.0では、エンコーディングを指定しないファイル入出力が、OSの言語・地域設定に関係なくUTF-8で処理される。また、モジュールを宣言しておき、実際に初めて使うときに読み込む遅延インポートが加わった。OSの設定に応じたエンコーディングを想定していたファイル処理コードは互換性の確認が必要で、起動時に多くのモジュールを読み込むコマンドラインツールには起動時間を短縮する余地が生まれる。
1. UTF-8はデフォルトであり、強制ではない
この変更はPEP 686に基づくもので、エンコーディングを省略したファイル入出力だけでなく、標準入出力やパイプにも適用される。エンコーディングを明示したコードは従来どおり動作する。
ほとんどのUnix環境はすでにUTF-8の設定を使っているため、影響は主にWindowsユーザーに及ぶ。従来の設定に依存していたプログラムでは文字化けやエラーが発生し、場合によってはエラーなしにデータが破損する可能性がある。
2. 依存箇所を見つけ、エンコーディングを指定する
確認の手順は単純だ。まず従来の動作に戻した状態で、エンコーディングを省略した箇所を警告で見つけ、そのコードに必要なエンコーディングを明示してから、新しいデフォルトで再びテストする。設定名は以下のとおりだ。
PYTHONUTF8=0 または -X utf8=0 UTF-8 モードを無効化
PYTHONWARNDEFAULTENCODING=1 または -X warn_default_encoding EncodingWarning を有効化
encoding="utf-8" / encoding="locale" エンコーディングを明示OSの設定に応じたエンコーディングが必須のファイルにはencoding="locale"を指定する。この値はUTF-8モードが有効でも従来の設定のエンコーディングを使う。
3. 宣言は上部に置き、読み込みは最初の使用まで遅らせる
PEP 810のlazyは、インポート文の前でのみ特別な意味を持つsoft keywordだ。lazyを付けたインポートは、名前に軽量な代理オブジェクトだけを結び付け、その名前を初めて使う瞬間に実際のモジュールを読み込む。
従来は、重いモジュールを遅れて読み込むために、インポート文を関数内へ移す方法がよく使われた。新しい方式は、インポート宣言をファイル上部にまとめたまま、使わないモジュールの読み込みだけを省く。この機能はモジュールのトップレベルでのみ使え、関数や例外処理ブロック内で使うと構文エラーになる。
4. 利点とコストがともに移る
以前のバージョンもサポートする必要があるライブラリは、lazyの代わりにモジュール名のリストを宣言する方式を使える。3.15ではリストにあるモジュールだけが遅延され、以前のバージョンでは宣言が無視されて通常どおり即座に読み込まれる。
__lazy_modules__ = ["json", "pathlib"]
import json # lazy
import os # still eager遅延可能なトップレベルのインポートをまとめて遅延対象にする実行オプションもあるが、PEP 810はライブラリ開発者にこのグローバル制御を推奨していない。遅延は、使わないモジュールが多いほど起動コストを減らす余地が大きい。一方、実際に使うモジュールの読み込みコストや読み込みエラー、プラグイン登録などの初期化処理は、最初に使う時点へ移る。インポート時の副作用に依存するコードは、明示的な初期化関数に変えるほうが安全だ。
UTF-8のデフォルト化は既存のエンコーディングへの依存を、遅延インポートは初期化のタイミングを再確認するきっかけとなる。
