ライブラリメンテナのための Python 型チェック最適化

ソースコードよりテストスイートの型チェックを優先する

ライブラリメンテナは、内部ソースコードでは 1 つの好みのチェッカーだけを使用し、テストスイートでは可能な限り多くの型チェッカーを実行することを優先すべきです。このアプローチにより、利用者がどの型チェッカーを使用していても、パブリック API が幅広いユーザーに対して互換性と利用可能性を保つことができます。

内部ソースコードに型チェッカーを実行すると、主に内部ロジックの検証が行われます。しかし、ライブラリの利用者は内部実装の詳細に触れることはなく、パブリック API とやり取りします。パブリック API を実行するテストスイートを複数のチェッカーで検証することで、メンテナは自分たちのコードベースのクリーンさを損なうことなく、利用者に一貫した開発体験を保証できます。

複数チェッカーによるソース検証のコスト

単一のソースファイルで複数の型チェッカーを満たそうとすると、冗長な type-ignore コメントが増え、コードが大幅に汚染されることがよくあります。mypy、Pyrefly、Pyright、ty、Zuban など、チェッカーごとに厳格さや Python 型仕様の解釈が異なるため、1 つの関数がすべてのチェッカーを通過するには複数の異なる ignore ディレクティブが必要になることがあります。

例えば、Polars ライブラリの DataType.__eq__ メソッドは、異なる戻り値型を扱うためにオーバーロードが必要です。mypy、Pyrefly、ty、Pyright のすべてを同時に満たすためには、たった 7 行のコード内に 4 つの異なる type-ignore コメントが必要になります。

@overload  # type: ignore[override]
def __eq__(  # pyrefly: ignore[bad-override]
    self, other: pl.DataTypeExpr
) -> pl.Expr: ...

@overload
def __eq__(self, other: PolarsDataType) -> bool: ...

def __eq__(self, other: pl.DataTypeExpr | PolarsDataType) -> pl.Expr | bool:  # ty: ignore[invalid-method-override]  # pyright: ignore[reportIncompatibleMethodOverride]

対照的に、この機能をテストするテストに対して同じチェッカーを実行すると、通常エラーは発生しません。チェッカーは内部実装の要件については意見が分かれるものの、パブリック API の期待される動作については概ね一致しているためです。

Python 型チェッカーの全体像を理解する

Python の型エコシステムは、mypy、Pyrefly、Pyright、ty、Zuban などの主要ツールで構成されています。公式の Python 型仕様には曖昧さがあり、特に不十分に指定された型情報の扱い方に違いがあるため、ツール間で差異が生じます。これにより、主に次の 2 つの設計哲学が生まれます:

  1. 厳格なチェッカー: これらのツールは潜在的なバグを防ぐことを優先し、最大の安全性を確保するために偽陽性を出すことがあります。Pyrefly は厳格で高速、かつ仕様準拠のオプションとして位置付けられています。
  2. 寛容なチェッカー: これらのツールは型ヒントの導入を段階的に行えるようにし、曖昧だが有効なコードをフラグ付けしにくくします。

コミュニティの視点と課題

開発者間の技術的議論は、現在の Python 型付けの状態に対するいくつかの体系的な不満を浮き彫りにしています。

  • 分散したエコシステム: 複数のチェッカーが必要とされることを、Python の型付けがネイティブな静的型付け言語に比べて「後付け」感がある証拠と見る開発者もいます。
  • パフォーマンスと推論: mypy などのレガシーツールの速度や、論理的に推論できる場面でも型を明示的に書く必要があることへの不満があります。
  • ツールの重複: ユーザーはツールごとに捕捉するエラーの種類が異なると報告しています。例えば、Pyright はオーバーロードに対して厳格で、mypy は None に関する問題をより効果的に検出するといった具合です。
  • AI との統合: 静的型付け言語は、確率的なコーディングエージェントを支える決定論的な基盤を提供するため、AI 支援コーディングに優れていると主張する人もいます。

"The whole type checking experience in python has disappointed me deeply... the language is quickly running blindly to the worst of all worlds in regards to typing."

「Python の型チェック全体の体験は私を深く失望させました…型に関しては、言語は最悪の世界へと盲目的に走っているようです。」

推奨戦略のまとめ

コード品質と保守コストのバランスを取るために、ライブラリメンテナは以下の階層を採用すべきです。

  • ソースコード: 1 つの型チェッカー(例: 厳格さと速度のための Pyrefly)を使用して内部の一貫性を保ちます。
  • テストスイート: 複数の型チェッカー(mypy、Pyright、ty など)を CI パイプラインに統合し、エコシステム全体でパブリック API の互換性を検証します。

Sources