mypyでユニオン型のパターンマッチの型推論がうまくいかなった話

131 Views

October 20, 24

スライド概要

2024/10/19(ゆるIT勉強会浜松) 土曜のIT勉強会で発表した資料です。
イベントページ: https://progdojo-hmmt.connpass.com/event/332298/

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

mypyでユニオン型のパターンマッチ の型推論がうまくいかなった話 2024/10/19 ゆるIT勉強会浜松 発表者: imamuray

2.

エラーになった状況 左のようなコード※があったので match 文を使って右に書き換えたら mypy でエラーが出た mypy の型チェックはエラーになるが、左も右も実行すると想定通りに動作する ※今回の説明のために、実際に書いていたコードを簡略化したものをサンプルコードとしている 実行環境: Python 3.11.10, mypy 1.12.0 書き換え前のサンプルコード 書き換え後のサンプルコード ユニオン型の left とright を型で条件分岐させたい 型の条件分岐なのでパターンマッチを使いたかった

3.

おさらい: mypy ● ● Python の静的型チェッカー 型にエラーがあるときに教えてくれる vscode で mypy 拡張機能を使ったとき、型エラーがあると赤い波線を出してくれる ↑の例の説明 ● 1行目: input() から返る型は str なので number の型は str ● 2行目: str 型の number と型が異なる int 型の 1 を + しようとして型チェックエラー

4.

おさらい: Python の match文 ● ● Python 3.10 から導入された文 Rust や Haskell などの関数型言語によくあるパターンマッチと似たようなこ とができる Rust の match 引用:https://doc.rust-lang.org/rust-by-example/flow_control/match.html Python の match 引用:https://peps.python.org/pep-0636/

5.

今回の書き換えの経緯 Python の match も関数型言語のパターンマッチと同じく書けるのでは? → 書いてみた結果、動くけど mypy の型チェックエラー Rust のサンプルコード Rust で今回書きたかった処理を書くとこうなる Python コード(再掲)

6.

mypy エラーが出たコードの詳細 left, right が None の場合を網羅 これ以降は l, r も None ではないの で、int の比較になっていてほしい。 → しかし mypy だと l, r ともに 「int | None」と推論する。 l, r が比較演算子が使えない None の 可能性があるためエラー

7.

軽く調べた結果 ● mypy の issue として上がっていた ○ ○ ● Match statement with tuple of union type fails ■ https://github.com/python/mypy/issues/15426 issue にあるコメント曰く、バグではなく mypy の仕様とのこと ■ https://github.com/python/mypy/issues/15426#issuecomment-1589505882 ● pyright (mypy とは別の型チェッカー)のコントリビューターのコメント ● > I think this is by design. This should probably be considered an enhancement request, not a bug. 今回のケースは mypy ではエラーになったが、pyright の型チェックではエ ラーにならず想定通りに推論される ○ issue のコメントにある通り、mypy と pyright で設計思想が違うためらしい

8.

結局エラーをどう対処したか mypy チェックは無効にすることも可能 type: ignore と書くとその部分の チェックを無効化できる 無効化が増えると、せっかくの型チェックの 恩恵が受けられなくなるので微妙... → 型チェックを無効にしてまで match 文で書く必要はなかったので、元の if 文のまま にすることにした