既稿では、 Ruby 4.0 への移行時に、言語仕様、標準ライブラリ、警告、周辺ツールを分けて確認する必要があると整理した[1]。 Python も同様に、同じ 3.x 系であれば無条件に互換であるわけではない。 PEP 387 は公開 API の後方互換性と非推奨手続きを定めているが、個々のコードがどの版で動くかを保証するものではない[2]。各版の変更点も、公式の What’s New を版ごとに確認する必要がある[3]。
後方互換性を維持するには、対応バージョンを文書へ書くだけでは足りない。古い処理系がソースを構文解析できること、実行時に必要な標準ライブラリと挙動が残っていること、新しい処理系で非推奨や既定値変更を踏まないことを、別々に確認しなければならない。本稿では、 Python 3.1 から 3.14 までの全変更を年表へ並べるのではなく、互換性を証明するために何を検査すべきかを整理する。
互換性は一つの性質ではない
ある Python ファイルが「 Python 3.1 以降で動く」という主張には、少なくとも三つの条件が含まれる。
| 互換性の層 | 確認する内容 | 典型的な破壊 |
|---|---|---|
| 構文 | 最小対応版の構文解析器がソース全体を読めること。 | f-string 、 async / await 、 match / case など、新しい文法を古い処理系へ持ち込む。 |
| 実行時 API | 使用する関数、クラス、モジュール、引数、例外の挙動が対象版に存在すること。 | 新しい API の利用、標準ライブラリからのモジュール削除、引数や返却値の変更。 |
| 運用時挙動 | 既定値、警告、プロセス生成、アノテーション評価などが想定どおりであること。 | コードは起動するが、最新版で処理順、初期化、直列化、検査結果が変わる。 |
三つの層は破壊される方向も異なる。 f-string を導入すると、最新版では動いても Python 3.5 以前では構文エラーになる。反対に、削除された標準ライブラリへ依存すると、古い版では動いても新しい版で失敗する。両者を同じ「後方互換性を壊す変更」とだけ呼ぶと、どの版で何を検査すべきかが分からなくなる。
対応方針は完全対応と最善努力を分ける
scripts リポジトリの実装方針は、 Python 3.6 以降を完全対応とし、 Python 3.1 までの互換性を最善努力で維持すると定めている[4]。この二層化は、古い版への配慮と、実際に保証する範囲を分けるために必要である。
同方針は、最低版を上げる機能の混入検査に find_pycompat.py を使用すると定めている[5]。ただし、この検査が担当するのは完全対応の証明ではなく、最善努力範囲を狭める機能の早期発見である。
ただし、「完全対応」は単なる禁止事項の一覧では成立しない。対象版で構文検査、単体テスト、コマンドライン処理、終了コード、ファイル入出力を反復して確認できることが必要である。実行環境を用意せず、ソースに新構文が見当たらないことだけを確認した場合、その版への対応は最善努力に留まる。
最善努力の範囲では、既存の動作を意図的に壊さず、最低版を上げる機能を不用意に持ち込まないことが中心になる。一方、対象版固有の標準ライブラリ挙動、プラットフォーム差、依存先まで継続的に試験できない以上、完全な動作保証とは区別しなければならない。
互換性境界は追加、予約語化、削除、挙動変更に分ける
実務で注意すべき境界は、全マイナーバージョンへ均等に存在するわけではない。既存コードへ影響する経路が明確な版を抽出すると、次のように整理できる。
| 境界 | 変更の種類 | 壊れる方向 | 検査対象 |
|---|---|---|---|
| Python 3.6 | PEP 498 により f-string が追加された[6]。 | 新しい構文を使うと、 Python 3.5 以前がソースを読めない。 | 最小対応版での構文検査。 |
| Python 3.7 | async と await が正式な予約語になった[7]。 | 以前に識別子として使えたコードが、 Python 3.7 以降で構文エラーになる。 | 古いコードの識別子と生成コード。 |
| Python 3.9 | collections に残されていた抽象基底クラスの互換別名が削除された[8]。 | 古い import が新しい処理系で失敗する。 | import 文と遅延 import 。 |
| Python 3.10 | PEP 634 の構造的パターンマッチが導入された[9][10]。 | match と case はソフトキーワードであり、通常の識別子を一律に禁止しない。ただし新構文は旧版で読めず、独自パーサーは対応が必要になる。 | 構文の最低版と、コード解析ツール。 |
| Python 3.12 | PEP 632 に従い distutils が標準ライブラリから削除された[11][12]。 | ビルド処理だけでなく、実行時に distutils を import するコードが失敗する。 | 配布設定、補助スクリプト、暗黙の setuptools 依存。 |
| Python 3.13 | PEP 594 の対象モジュールと lib2to3 が削除された[13][14]。 | 旧モジュールを標準搭載とみなすコードや、 lib2to3 を解析器として使うツールが失敗する。 | 全 import 、コード変換、構文解析、運用環境の追加依存。 |
| Python 3.14 | PEP 649 と PEP 749 に基づき、アノテーションの評価と取得方法が変更された[15][16]。 POSIX 環境では multiprocessing の既定開始方式も fork から forkserver へ変更された[17]。 | アノテーションを実行時に直接読む処理や、 fork 継承を暗黙に期待する並列処理で挙動差が生じる。 | __annotations__ の直接参照、型情報を読むライブラリ、プロセス生成、直列化。 |
この表は Python 3.1 から 3.14 までの変更履歴を要約するものではない。互換性を壊す経路が異なる代表的な境界を選び、必要な検査へ結びつけたものである。各版に新機能が追加されたという事実だけでは、既存コードへの影響を説明できない。
find_pycompat.py は禁止機能の混入を検出する
find_pycompat.py は、 f-string 、 subprocess.run 、 subprocess.DEVNULL 、 async / await 、型ヒント、 nonlocal 、行列積演算子、 asyncio 、 yield from 、 pathlib 、 shutil.which などを正規表現で探索する[5]。リポジトリ方針で使用を避ける機能が混入したとき、レビュー前に候補箇所を列挙できる。
この検査が証明するのは、登録された文字列パターンが検出されなかったことまでである。正規表現は Python の構文木や import 解決結果を解析していないため、別名 import 、動的 import 、複数行に分かれた記述、依存パッケージ内部の最低版、標準ライブラリの削除、既定値変更までは判定できない。逆に、文字列リテラルや文脈によっては誤検出も起こり得る。
したがって、 find_pycompat.py は最善努力範囲への新機能混入を止める検査として使い、対応版を証明する試験の代わりにはしない。検出対象を増やす場合も、追加した正規表現が何を検出でき、何を検出できないかをテストで固定する必要がある。
最低版と最新版では異なる試験を行う
最低対応版では、ソースを実際に構文解析し、起動し、主要経路を実行する。 py_compile は指定した Python 処理系で個別のソースをコンパイルし、構文エラー時に非ゼロで終了できる[18]。ディレクトリ全体には compileall を使える[19]。ただし、 Python 3.14 で compileall を実行しても、 Python 3.6 で読めることは証明できない。必ず検査対象の最低版自身で実行する。
最新版では、削除済み API 、非推奨警告、既定値変更、実行時仕様の差を確認する。 DeprecationWarning は通常の実行で表示されない場合があるため、開発時には -W default で可視化し、修正対象を限定したうえで -W error による失敗化を検討する[20]。警告を一律にエラー化すると、外部依存の警告で試験全体が停止するため、カテゴリと発生元を確認して段階的に適用する。
完全対応範囲の中間版も無視できない。最低版と最新版だけでは、特定版で導入され、後の版で修正された挙動差を見落とす可能性がある。ただし全版を常時実行できない場合でも、最低版、運用中の主要版、最新版の三点は分けて検査すべきである。
互換性の宣言をコードと検査へ一致させる
配布物であれば、 Requires-Python はインストール可能な Python 版をパッケージ管理ツールへ伝えるメタデータである[21]。スクリプト集でも同じ考え方が必要であり、ヘッダーに書く最低版は、実際に構文検査と試験を行う最低版と一致させる。
| 宣言 | 必要な証拠 | 不足した場合の扱い |
|---|---|---|
| 完全対応 | 対象版での構文検査、テスト、主要な実運用経路、終了コードの継続確認。 | 試験できない版は完全対応から外す。 |
| 最善努力 | 禁止機能の静的検査、意図的な最低版引き上げの禁止、既存利用者からの不具合確認。 | 動作保証ではないことを文書へ明示する。 |
| 非対応 | 最低版を上げる理由、必要となった機能、移行方法の記録。 | 曖昧なまま古い版を残さない。 |
最低版を高く書けば安全になるわけではない。実際には Python 3.2 で動くコードへ Python 3.6 以上と記載すれば、利用可能な環境を理由なく狭める。反対に、試験していない Python 3.1 を完全対応と書けば、検証していない保証を作る。宣言は、使用した文法の新しさではなく、継続して提示できる検証結果に合わせる必要がある。
Python の互換性は検査の組み合わせで維持する
Python 3.x の互換性問題は、各マイナーバージョンの変更点を一枚の表へ並べても解決しない。新構文は古い処理系を壊し、 API 削除は新しい処理系を壊し、既定値や評価時期の変更は両方で起動できるコードの挙動を変える。それぞれ別の検査が必要である。
scripts リポジトリでは、 find_pycompat.py による禁止機能の検出を残しつつ、完全対応範囲では対象処理系による構文検査と実行試験を行う。最新版では警告、削除、既定値変更を確認し、最善努力の旧版については保証範囲を広げすぎない。この分担により、静的検査を動作保証と誤認せず、対応バージョンの宣言を実際の検証能力へ一致させられる。
後方互換性とは、古い書き方を保存することではない。最低版で読めること、新しい版で壊れないこと、両者の間で必要な挙動が維持されることを、異なる検査で継続的に確認する運用である。
参考文献
- id774, Ruby 4.0 新機能と Ruby 3.x 系コードの互換性維持で注意すべき点(2025-12-26). https://blog.id774.net/entry/2025/12/26/3138/
- Python Software Foundation, “PEP 387 – Backwards Compatibility Policy,” 2009. https://peps.python.org/pep-0387/
- Python Software Foundation, “What’s New in Python.” https://docs.python.org/3/whatsnew/index.html
- id774, “Implementation Policies,” scripts Repository. https://github.com/id774/scripts/blob/master/doc/POLICY
- id774, “find_pycompat.py,” scripts Repository. https://github.com/id774/scripts/blob/master/find_pycompat.py
- Python Software Foundation, “PEP 498 – Literal String Interpolation,” 2015. https://peps.python.org/pep-0498/
- Python Software Foundation, “What’s New In Python 3.7,” 2018. https://docs.python.org/3/whatsnew/3.7.html
- Python Software Foundation, “What’s New In Python 3.9,” 2020. https://docs.python.org/3/whatsnew/3.9.html
- Python Software Foundation, “PEP 634 – Structural Pattern Matching: Specification,” 2020. https://peps.python.org/pep-0634/
- Python Software Foundation, “What’s New In Python 3.10,” 2021. https://docs.python.org/3/whatsnew/3.10.html
- Python Software Foundation, “PEP 632 – Deprecate distutils module,” 2020. https://peps.python.org/pep-0632/
- Python Software Foundation, “What’s New In Python 3.12,” 2023. https://docs.python.org/3/whatsnew/3.12.html
- Python Software Foundation, “PEP 594 – Removing dead batteries from the standard library,” 2019. https://peps.python.org/pep-0594/
- Python Software Foundation, “What’s New In Python 3.13,” 2024. https://docs.python.org/3/whatsnew/3.13.html
- Python Software Foundation, “PEP 649 – Deferred Evaluation Of Annotations Using Descriptors,” 2021. https://peps.python.org/pep-0649/
- Python Software Foundation, “PEP 749 – Implementing PEP 649,” 2023. https://peps.python.org/pep-0749/
- Python Software Foundation, “What’s New In Python 3.14,” 2025. https://docs.python.org/3/whatsnew/3.14.html
- Python Software Foundation, “py_compile — Compile Python source files.” https://docs.python.org/3/library/py_compile.html
- Python Software Foundation, “compileall — Byte-compile Python libraries.” https://docs.python.org/3/library/compileall.html
- Python Software Foundation, “warnings — Warning control.” https://docs.python.org/3/library/warnings.html
- Python Packaging Authority, “Core metadata specifications: Requires-Python.” https://packaging.python.org/en/latest/specifications/core-metadata/#requires-python