Pythonでの演算子のオーバーロード
Pythonでの演算子のオーバーロードは特殊メソッドで実現できます。
全部網羅してるわけではないですが、いくつか列挙してみます。
比較演算子系のオーバーロード
特殊メソッド名 | 例 |
---|---|
__lt__(self, other) | self < other |
__le__(self, other) | self <= other |
__eq__(self, other) | self == ohter |
__ne__(self, other) | self != other |
__gt__(self, other) | self > other |
__ge__(self, other) | self >= other |
特殊メソッドが呼ばれているかprintを入れて確認してみます。
class Foo(): def __init__(self,x): self.__x = x def __lt__(self, other): print("__lt__") return self.__x < other def __le__(self, other): print("__le__") return self.__x <= other def __eq__(self, other): print("__eq__") return self.__x == other def __ne__(self, other): print("__ne__") return self.__x != other def __gt__(self, other): print("__gt__") return self.__x > other def __ge__(self, other): print("__ge__") return self.__x >= other x = Foo(100) x < 10 x <= 10 x == 10 x != 10 x > 10 x >= 10
$ py main.py __lt__ __le__ __eq__ __ne__ __gt__ __ge__
算術演算子系のオーバーロード(左辺)
特殊メソッド名 | 例 |
---|---|
__add__(self, other) | self + other |
__sub__(self, other) | self - other |
__mul__(self, other) | self * other |
__truediv__(self, other) | self / other |
__floordiv__(self, other) | self // other |
__mod__(self, other) | self % other |
__pow__(self, other) | self ** other |
__lshift__(self, other) | self << other |
__rshift__(self, other) | self >> other |
__and__(self, other) | self & other |
__xor__(self, other) | self ^ other |
__or__(self, other) | self | other |
これは基本的には計算結果をreturnするだけなのですが、注意点としては自身と同じクラスの別オブジェクトとして返すところですね。
class Foo(): def __init__(self,x): self.__x = x def __add__(self, other): print("__add__") return self.__class__(self.__x + other) def __sub__(self, other): print("__sub__") return self.__class__(self.__x - other) def __mul__(self, other): print("__mul__") return self.__class__(self.__x * other) def __truediv__(self, other): print("__truediv__") return self.__class__(self.__x / other) def __floordiv__(self, other): print("__floordiv__") return self.__class__(self.__x // other) def __mod__(self, other): print("__mod__") return self.__class__(self.__x % other) def __pow__(self, other): print("__pow__") return self.__class__(self.__x ** other) def __lshift__(self, other): print("__lshift__") return self.__class__(self.__x << other) def __rshift__(self, other): print("__rshift__") return self.__class__(self.__x >> other) def __and__(self, other): print("__and__") return self.__class__(self.__x & other) def __xor__(self, other): print("__xor__") return self.__class__(self.__x ^ other) def __or__(self, other): print("__or__") return self.__class__(self.__x | other) x = Foo(100) x + 10 x - 10 x * 10 x / 10 x // 10 x % 10 x ** 10 x << 10 x >> 10 x & 10 x ^ 10 x | 10
$ py main.py __add__ __sub__ __mul__ __truediv__ __floordiv__ __mod__ __pow__ __lshift__ __rshift__ __and__ __xor__ __or__
ちなみにreturn時にFooを使わずにself.__class__を使っているのは継承を考慮した場合の書き方です。
算術演算子系のオーバーロード(右辺)
特殊メソッド名 | 例 |
---|---|
__radd__(self, other) | other + self |
__rsub__(self, other) | other - self |
__rmul__(self, other) | other * self |
__rtruediv__(self, other) | other / self |
__rfloordiv__(self, other) | other // self |
__rmod__(self, other) | other % self |
__rpow__(self, other) | other ** self |
__rlshift__(self, other) | other << self |
__rrshift__(self, other) | other >> self |
__rand__(self, other) | other & self |
__rxor__(self, other) | other ^ self |
__ror__(self, other) | other | self |
先ほどのは左辺のクラスの場合の特殊メソッドでしたが、こちらは対象が右辺のクラスの場合に動作します。
つまり「x + 10」ならx.__add__(10)が起動し、「10 + x」ならx.__radd__(10)が起動するといったかんじです。
実際に__radd__の動作確認をしてみます。
class Foo(): def __init__(self,x): self.__x = x def __add__(self, other): print("__add__") return self.__class__(self.__x + other) def __radd__(self, other): print("__radd__") return self.__class__(self.__x + other) x = Foo(100) x + 10 10 + x
$ py main.py __add__ __radd__
さてここで疑問が生じます、左辺のクラスに__add__が存在し、右辺のクラスに__radd__が存在する場合はどちらが呼ばれるんでしょう。
class Foo(): def __add__(self, other): print("__add__") class Bar(): def __radd__(self, other): print("__radd__") x = Foo() y = Bar() x + y
$ py main.py __add__
両方存在している場合は__add__が優先されるかんじですね。
算術代入演算子系のオーバーロード
__iadd__(self, other) | self += other |
__isub__(self, other) | self -= other |
__imul__(self, other) | self *= other |
__itruediv__(self, other) | self /= other |
__ifloordiv__(self, other) | self //= other |
__imod__(self, other) | self %= other |
__ipow__(self, other) | self **= other |
__ilshift__(self, other) | self <<= other |
__irshift__(self, other) | self >>= other |
__iand__(self, other) | self &= other |
__ixor__(self, other) | self ^= other |
__ior__(self, other) | self |= other |
これは計算した後、自身への代入を行う演算子のオーバーロードですね。
内部的にはselfの値を変更しselfをreturnすると辻褄が合います。
class Foo(): def __init__(self,x): self.__x = x def __iadd__(self, other): print("__iadd__") self.__x += other return self def __isub__(self, other): print("__isub__") self.__x -= other return self def __imul__(self, other): print("__imul__") self.__x *= other return self def __itruediv__(self, other): print("__itruediv__") self.__x /= other return self def __ifloordiv__(self, other): print("__ifloordiv__") self.__x //= other return self def __imod__(self, other): print("__imod__") self.__x %= other return self def __ipow__(self, other): print("__ipow__") self.__x **= other return self def __ilshift__(self, other): print("__ilshift__") self.__x <<= other return self def __irshift__(self, other): print("__irshift__") self.__x >>= other return self def __iand__(self, other): print("__iand__") self.__x &= other return self def __ixor__(self, other): print("__ixor__") self.__x ^= other return self def __ior__(self, other): print("__ior__") self.__x |= other return self x = Foo(100) x += 1 x = Foo(100) x -= 1 x = Foo(100) x *= 1 x = Foo(100) x /= 1 x = Foo(100) x //= 1 x = Foo(100) x %= 1 x = Foo(100) x **= 1 x = Foo(100) x <<= 1 x = Foo(100) x >>= 1 x = Foo(100) x &= 1 x = Foo(100) x ^= 1 x = Foo(100) x |= 1
$ py main.py __iadd__ __isub__ __imul__ __itruediv__ __ifloordiv__ __imod__ __ipow__ __ilshift__ __irshift__ __iand__ __ixor__ __ior__
単項演算子系のオーバーロード
特殊メソッド名 | 例 |
---|---|
__neg__(self) | -self |
__pos__(self) | +self |
__invert__(self) | ~self |
単項演算子系です。これも確認しておきます。
class Foo(): def __init__(self,x): self.__x = x def __neg__(self): print("__neg__") return self.__class__(-self.__x) def __pos__(self): print("__pos__") return self.__class__(+self.__x) def __invert__(self): print("__invert__") return self.__class__(~self.__x) x = Foo(100) -x +x ~x
$ py main.py __neg__ __pos__ __invert__