実験:関数オーバーロード(続き)
pythonは型ヒントを無視するのでこうなるしかないんですけど
どうしてもオーバーロードするなら自分で型を判定する
ていうかUnion型があるってことはもともとそういうものってことかな
class Point:
def __init__(self,
x: Union[Tuple[float, float], float] = 0.0,
y: float=0.0) -> None:
if isinstance(x, tuple):
self.x = x[0]
self.y = x[1]
else:
self.x = x
self.y = y
mypyは通った
動かす
$ python3 -i shape.py
>>> Point()
Point(0.0, 0.0)
>>> Point(1.0,2.0)
Point(1.0, 2.0)
>>> Point((2.0,4.0))
Point(2.0, 4.0)
>>> Point(3.0)
Point(3.0, 0.0)
Ok
最後のはおまけだけど、そうなるよな
こうは書けない?
if isinstance(x, Tuple[float, float]):
self.x = x[0]
self.y = x[1]
書けない
$ python3 -i shape.py
>>> Point()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "shape.py", line 18, in __init__
if isinstance(x, Tuple[float, float]):
File "/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/typing.py", line 1261, in __instancecheck__
raise TypeError("Parameterized Tuple cannot be used "
TypeError: Parameterized Tuple cannot be used with isinstance().
Parameterized Tupleはダメって言ってるな
ということはこれならいけるのか?
if isinstance(x, Tuple):
self.x = x[0]
self.y = x[1]
いけた
$ python3 -i shape.py
>>> Point((2.0, 4.0))
Point(2.0, 4.0)
tupleと書くかTupleと書くかでなにか違ってくるのかな
なんとなくTupleと書いたほうが一貫性はありそうな気がする
オーバーロード的なことをやるfunctools.singledispatchというデコレータもあるようだけど
関数をデコレートするもので、メソッドをデコレートするものではない
そりゃそうだよな
メソッドはそもそもselfでシングルディスパッチするんだから
と思ったら
singledispatchを使ってメソッドでも同等のことができるようにする技が
stackoverflowには載っていた
python - How can I use functools.singledispatch with instance methods? - Stack Overflow
こういうデコレータを作って使う
from functools import singledispatch, update_wrapper
def methdispatch(func):
dispatcher = singledispatch(func)
def wrapper(*args, **kw):
return dispatcher.dispatch(args[1].__class__)(*args, **kw)
wrapper.register = dispatcher.register
update_wrapper(wrapper, func)
return wrapper
このコードを理解した上で使うかというとisinstanceとifで
いいんじゃないのって気もする
関数とかメソッドのオーバーロードって、既存のソースをいじらずに
新しい型に対応して拡張できるってところがいちばん嬉しいところだと思うので
一箇所にまとめて書くとなるとメリットが減るし