1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

記事投稿キャンペーン 「2024年!初アウトプットをしよう」

型による条件分岐みたいなことをメソッドでやろうとしたら mypy にエラーを出された

Posted at

へぇ〜となったので共有。

最初に結論

  • mypy の設定はデフォルト
  • 型による条件分岐は if isinstance(piyo, Type):とすればできる。
    • 読みやすくしようとif is_eatable(piyo):という形にすると mypy にエラーを出される。
  • じゃあ、どうする?
    • isinstance(...で満足する
      • 記事書き出して気づいたんですが、これでいいですね。コメントを書けばいい。
    • if is_eatable(piyo) and isinstace(...: みたいな書き方
      • andを使えば両辺が True じゃないと進めませんから mypy も満足してくれるようです。
        • 意味内容の面から言うと無。同じ if 文を 2 回書いているようなもの。

サンプルコード

正月.py
class Man:
    """mypy の動作チェッククラス"""

    def __init__(self) -> None:
        self.before_meshi: list[str | int] = []
        self.meshi_pattern: list[str | int] = ["おもち", "おせち", 0xDEADBEEF]

    def _eat(self, food: str) -> None:
        self.before_meshi.append(food)

    def is_eatable(self, food: str | int) -> bool:
        ```食べられるかチェックする```
        if isinstance(food, str):
            return True
        return False

    def meshi(self, food: str | int) -> None:
        # if isinstance(food, str): と同義のはずだが…
        # mypy_test.py:20: error: Argument 1 to "_eat" of "Man" has incompatible type "str | int"; expected "str"  [arg-type]
        if self.is_eatable(food):
            self._eat(food)
        return None

    def lookup_meshi(self) -> None:
        for meshi in self.before_meshi:
            print(f"{meshi}を食べました")


sato_san = Man()
sato_san.meshi(sato_san.meshi_pattern[0])
sato_san.meshi(sato_san.meshi_pattern[1])
sato_san.meshi(sato_san.meshi_pattern[2])
sato_san.lookup_meshi()
assert 0xDEADBEEF not in sato_san.before_meshi, "えっ、牛肉? 食べたけど?"

#おもちを食べました
#おせちを食べました

賀正

このコードは、sato_sanの正月シミュレーションを通して mypyの動作確認を行っています。

    def is_eatable(self, food: str | int) -> bool:
        if isinstance(food, str):
            return True
        return False

    def meshi(self, food: str | int) -> None:
        # if isinstance(food, str): と同義のはずだが…
        # mypy_test.py:20: error: Argument 1 to "_eat" of "Man" has incompatible type "str | int"; expected "str"  [arg-type]
        if self.is_eatable(food):
            self._eat(food)
        return None

意図としては条件文を考えなくて良いように、わかりやすい名前をつけようとしています。
この部分に、 mypy はエラーを出します。しかし、この部分を

    def meshi(self, food: str | int) -> None:
        if isinstance(food, str):
            self._eat(food)
        return None

とするとエラーが出ません。
どうやら、mypyは空気を読んでくれないようです。毎回ジャンプして読みに行っているわけではないのでしょう。
同様に関数内関数でも実験しましたが、エラーを出しました。

is_eatable()を使うために

    def is_eatable(self, food: str | int) -> bool:
        if isinstance(food, str):
            return True
        return False

    def meshi(self, food: str | int) -> None:
        if self.is_eatable(food) and isinstance(food, str):
            self._eat(food)
        return None

このようにすると、エラーがでなくなります。
ただ、一般的に両辺には別の条件を期待しますから、ちょっと考えた挙句なんの意味もないと気づくということが起こるでしょう。

mypyのエラーを避けるための小細工はコードを読む人には価値のない情報です。
isinstanceを使ってコメントを書くか、エラーを抑制してis_eatableを使うのが良いでしょう。

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?