Python

【Python】演算子をオーバーロードする特殊メソッドの使い方

この記事では、Pythonで演算子をオーバーロードする方法を解説します。intなどの組み込み型では、+-で演算できたり、==などの比較演算子で比較できます。

演算子のオーバーロードを行うことで、ユーザー定義型でも同じような振る舞いを持たせることができます。つまり、演算子のオーバーロードとは、ユーザー定義型で演算や比較を行えるようにするための機能です。

Pythonで演算子をオーバーロードするには、クラスに特殊メソッドを定義するだけで簡単に実装することができます。

それでは、特殊メソッドの使い方を見ていきましょう❗️

比較演算子の特殊メソッド

比較演算子用の特殊メソッドをクラスに定義することで、そのクラスで比較を行えるようにできます。

演算子 機能 特殊メソッド
< 小なり __lt__(self, other)
<= 小なりイコール __le__(self, other)
> 大なり __gt__(self, other)
>= 大なりイコール __ge__(self, other)
== 等しい __eq__(self, other)
!= 等しくない __ne__(self, other)

試しに、==で等しいか判定できるクラスを定義します。特殊メソッドのother引数には、比較対象のオブジェクトが渡されます。

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __eq__(self, other):
        # 同じクラスかどうかの判定
        if type(other) == Num: 
            return self.num == other.num
        raise TypeError()

# インスタンス化
zero1 = Num(0)
one = Num(1)
zero2 = Num(0)

print(f'zero1 == one: {zero1 == one}')
print(f'zero1 == zero2: {zero1 == zero2}')

実行結果

zero1 == one: False
zero1 == zero2: True

他の特殊メソッドも同じ要領で実装できます。

算術演算子(左辺)の特殊メソッド

算術演算子(左辺)の特殊メソッドを見ていきます。ここで紹介する特殊メソッドは、計算時に自身が左辺の場合に呼び出されます。 

A + B の時は、Aが左辺でBが右辺となります
演算子 機能 特殊メソッド
+ 足し算 __add__(self, other)
引き算 __sub__(self, other)
* 掛け算 __mul__(self, other)
/ 割り算 __truediv__(self, other)
// 切り捨て割り算 __floordiv__(self, other)
% 剰余(余り) __mod__(self, other)
** べき乗 __pow__(self, other)

試しに、+で足し算ができるクラスを定義してみます。

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __add__(self, other):
        # 同じクラスかどうかの判定
        if type(other) == Num: 
            return self.num + other.num
        raise TypeError()

# インスタンス化
one = Num(1)
two = Num(2)

print(f'one + two = {one + two}')

実行結果

one + two = 3

算術演算子(右辺)の特殊メソッド

計算時に自身が右辺の場合に呼び出される特殊メソッドです。

特殊メソッドが左辺と右辺のどちらも定義されている場合は、左辺の特殊メソッドが優先されます
演算子 機能 特殊メソッド
+ 足し算 __radd__(self, other)
引き算 __rsub__(self, other)
* 掛け算 __rmul__(self, other)
/ 割り算 __rtruediv__(self, other)
// 切り捨て割り算 __rfloordiv__(self, other)
% 剰余(余り) __rmod__(self, other)
** べき乗 __rpow__(self, other)

試しに、+で足し算ができるクラスを定義します。しかし、先ほどの特殊メソッドと違い、左辺に置くことはできません。

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __radd__(self, other):
        if type(other) == int:
            return self.num + other

# インスタンス化
one = Num(1)

print(f'2 + one = {2 + one}')

# 以下のように左辺に置くとエラー
one + 2

実行結果

2 + one = 3

算術代入演算子の特殊メソッド

代入演算子を実装するための特殊メソッドも用意されています。

機能 特殊メソッド
+= __iadd__(self, other)
-= __isub__(self, other)
*= __imul__(self, other)
/= __itruediv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

例として、+=で代入演算できるクラスを定義します。

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __iadd__(self, other):
        if type(other) == Num:
            self.num +=  other.num
            return self

# インスタンス化
one = Num(1)
two = Num(2)

# 計算
one += two

print(f'one += two = {one.num}')

実行結果

one += two = 3

単項演算子の特殊メソッド

単項演算子も特殊メソッドで実装することができます。

機能 特殊メソッド
+instance __pos__(self)
-instance __neg__(self)
~instance __invert__(self)

試しに、+instanceで、インクリメントできるクラスを定義します。

class Num:
    def __init__(self, num):
        self.num = num
    
    # 特殊メソッド
    def __pos__(self):
        self.num += 1
        return self.num

# インスタンス化
zero = Num(0)

# 単項演算
+zero

print(f'zero.num = {zero.num}')
print(f'zero.num = {+zero}')

実行結果

zero.num = 1
zero.num = 2

まとめ

この記事では、Pythonの演算子のオーバーロードをする方法を解説しました。

演算子のオーバーロードを実装することで、組み込み型に似たユーザー定義型を作成することができます。比較や演算をよく行うクラスでは、あらかじめオーバーロードしておくと便利です。

ただし、全く使わないような特殊メソッドは、定義しても邪魔にしかならないので必要なメソッドのみを定義しましょう!

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ

最短3か月でエンジニア転職『DMM WEBCAMP COMMIT』