Python 3.x 系の互換性維持で注意すべき点

既稿では、 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 による禁止機能の検出を残しつつ、完全対応範囲では対象処理系による構文検査と実行試験を行う。最新版では警告、削除、既定値変更を確認し、最善努力の旧版については保証範囲を広げすぎない。この分担により、静的検査を動作保証と誤認せず、対応バージョンの宣言を実際の検証能力へ一致させられる。

後方互換性とは、古い書き方を保存することではない。最低版で読めること、新しい版で壊れないこと、両者の間で必要な挙動が維持されることを、異なる検査で継続的に確認する運用である。


参考文献

  1. id774, Ruby 4.0 新機能と Ruby 3.x 系コードの互換性維持で注意すべき点(2025-12-26). https://blog.id774.net/entry/2025/12/26/3138/
  2. Python Software Foundation, “PEP 387 – Backwards Compatibility Policy,” 2009. https://peps.python.org/pep-0387/
  3. Python Software Foundation, “What’s New in Python.” https://docs.python.org/3/whatsnew/index.html
  4. id774, “Implementation Policies,” scripts Repository. https://github.com/id774/scripts/blob/master/doc/POLICY
  5. id774, “find_pycompat.py,” scripts Repository. https://github.com/id774/scripts/blob/master/find_pycompat.py
  6. Python Software Foundation, “PEP 498 – Literal String Interpolation,” 2015. https://peps.python.org/pep-0498/
  7. Python Software Foundation, “What’s New In Python 3.7,” 2018. https://docs.python.org/3/whatsnew/3.7.html
  8. Python Software Foundation, “What’s New In Python 3.9,” 2020. https://docs.python.org/3/whatsnew/3.9.html
  9. Python Software Foundation, “PEP 634 – Structural Pattern Matching: Specification,” 2020. https://peps.python.org/pep-0634/
  10. Python Software Foundation, “What’s New In Python 3.10,” 2021. https://docs.python.org/3/whatsnew/3.10.html
  11. Python Software Foundation, “PEP 632 – Deprecate distutils module,” 2020. https://peps.python.org/pep-0632/
  12. Python Software Foundation, “What’s New In Python 3.12,” 2023. https://docs.python.org/3/whatsnew/3.12.html
  13. Python Software Foundation, “PEP 594 – Removing dead batteries from the standard library,” 2019. https://peps.python.org/pep-0594/
  14. Python Software Foundation, “What’s New In Python 3.13,” 2024. https://docs.python.org/3/whatsnew/3.13.html
  15. Python Software Foundation, “PEP 649 – Deferred Evaluation Of Annotations Using Descriptors,” 2021. https://peps.python.org/pep-0649/
  16. Python Software Foundation, “PEP 749 – Implementing PEP 649,” 2023. https://peps.python.org/pep-0749/
  17. Python Software Foundation, “What’s New In Python 3.14,” 2025. https://docs.python.org/3/whatsnew/3.14.html
  18. Python Software Foundation, “py_compile — Compile Python source files.” https://docs.python.org/3/library/py_compile.html
  19. Python Software Foundation, “compileall — Byte-compile Python libraries.” https://docs.python.org/3/library/compileall.html
  20. Python Software Foundation, “warnings — Warning control.” https://docs.python.org/3/library/warnings.html
  21. Python Packaging Authority, “Core metadata specifications: Requires-Python.” https://packaging.python.org/en/latest/specifications/core-metadata/#requires-python