へぇ〜となったので共有。
最初に結論
-
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
を使うのが良いでしょう。