16章 計算幾何学 (続き)
あとはやりながら必要になったら調べていこう
ということでライブラリづくりの続き
ちょっとだけ型をつけてみる
class Point():
def __init__(self, x: float=0.0, y: float=0.0) -> None:
self.x: float = x
self.y: float = y
def __eq__(self, other: Point) -> bool:
return self.x == other.x and self.y == other.y
__init__でself.xはfloatだって言ったことは
__eq__の中でも覚えててくれるのかなあ
さらにはother.xもfloatなんだってことはわかってる?
mypyにかけてみる
$ mypy shape.py
shape.py:6: error: Argument 1 of "__eq__" incompatible with supertype "object"
shape.py:6: note: It is recommended for "__eq__" to work with arbitrary objects, for example:
shape.py:6: note: def __eq__(self, other: object) -> bool:
shape.py:6: note: if not isinstance(other, Point):
shape.py:6: note: return NotImplemented
shape.py:6: note: return <logic to compare two Point instances>
あそうか
otherにPoint型が入ってるとは限らないもんね
コードの例までつけてくれて・・・
ん そうか?
型チェックするんだからPointが入らないようなコードは事前に
チェックしてくれて、実行時に自分でチェックしなくていいように
してくれたほうがうれしい気もするけど?
でもこのコード、pythonが通してくれない
$ shape.py
Traceback (most recent call last):
File "./shape.py", line 4, in <module>
class Point():
File "./shape.py", line 9, in Point
def __eq__(self, other: Point) -> bool:
NameError: name 'Point' is not defined
そういえば前方参照についても書いてあったな
えーと、文字列にするのか
すごい解決策だな
こういうことか
def __eq__(self, other: 'Point') -> bool:
return self.x == other.x and self.y == other.y
どれどれ
$ shape.py
$
通ったな
でもmypyさんが同じエラーを出してくる
言われたとおりにするか
いやそのまえに型ヒントだけ変えてみよう
def __eq__(self, other: object) -> bool:
return self.x == other.x and self.y == other.y
pythonは通してくれる
mypyは
$ mypy shape.py
shape.py:10: error: "object" has no attribute "x"
shape.py:10: error: "object" has no attribute "y"
そうか、object型にはxもyもないもんな
ってじゃあどうなるのよ
こうしたら解決するっていうの?
def __eq__(self, other: object) -> bool:
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y
解決した
$ shape.py
$ mypy shape.py
$
賢いな
型だけ見てるんじゃなくて、
not isinstance(other, Point):
じゃないってことから
otherはPoint型だ、ってことまで理解してるのか
Typed Racketでも似たようなことしてたな
そこまで理解してるってことは↓くらいは余裕で理解してるんだろうな
__init__でself.xはfloatだって言ったことは
__eq__の中でも覚えててくれるのかなあ
さらにはother.xもfloatなんだってことはわかってる?